日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

模拟赛 yjqb

發(fā)布時間:2025/3/21 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模拟赛 yjqb 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

對于這種“不能交叉”的條件,不是很好處理。那么就考慮一下dp

dp[i][j]表示,考慮A中用前i個,考慮連接B中用前j個,最大匹配。(類似LCS的DP)

轉(zhuǎn)移:dp[i][j]=max(dp[i][j-1],dp[i-1][j])當li<=j<=ri時,dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1)

這樣可以保證一定不會交叉,而且不會共用匹配點

O(N^2)

?

看起來非常無法優(yōu)化。而且我們還沒有好好利用區(qū)間連邊的特點。

觀察轉(zhuǎn)移的特點,

一個發(fā)現(xiàn)是,這是一個前綴取max,并且某些dp數(shù)值的位置+1

由于要和前面的i取max,

那么,把函數(shù)鍵值化,

對于考慮到第i個點,

圖像是:

一個分段函數(shù)!

考慮如果新加入一個點i的話,在此基礎(chǔ)上造成什么影響。

為了方便理解,考慮用滾動數(shù)組

?

dp[j]=max(dp[j],dp[j-1]+1)

這個dp[j]可以直接理解為上一次留下的dp值。(當然轉(zhuǎn)移是倒序循環(huán))

dp[j]=max(dp[j-1],dp[j])這個要正序循環(huán)

發(fā)現(xiàn),對于分段函數(shù)造成的影響,是一段區(qū)間!

由于dp[j]=max(dp[j],dp[j-1]+1),注意每個分段函數(shù)的左端點是不會變化的。

并且,+1的轉(zhuǎn)移都是dp[j]=max(dp[j],dp[j-1]+1)

所以,分段函數(shù)的落差都恰好是1!!!

?

如果可以維護好分段函數(shù),那么最后最高的函數(shù)就是ans

怎么維護?

發(fā)現(xiàn)這個函數(shù)的變化,本質(zhì)上是把更新區(qū)間中涉及到的分段函數(shù)向右移動一步,再向上移動一步得到的新的圖像!

于是可以打標記了!

這個函數(shù)的區(qū)間提取,如果用線段樹做的話,提取會非常麻煩。而且左移上移怎么處理?!?!

這么靈活的移動,只能交給平衡樹了!

ywy_c_asm的大力討論法:

用三元組[l,r,val]表示每個分段函數(shù)的左右端點和高度(函數(shù)值)

很多麻煩的事情:

1.邊界涉及到函數(shù)分離,函數(shù)合并。

2.邊界可能是某些函數(shù)的左端點,

3.和后面的合并?沒有后繼怎么辦?

4.[L,R]只有一個分段函數(shù)?要特判

5.[L,R]有兩個分段函數(shù)?由于不能直接把后面的函數(shù)合并到前驅(qū)再--r那么簡單(其實好像可以?)反正特判比較保險

6.[L,R]有多個分段函數(shù)?這時候就要區(qū)間打標記了。

7.merge函數(shù)那個并入哪一個?

8.split函數(shù),從哪里斷開?剩下的l,r是什么?

還有一些splay的基本操作(我寫的splay)

1.pre,bac前驅(qū)后繼,記得pushdown

2.kth,記得pushdown

3.tag的標記打好。

4.左右位置放上空節(jié)點方便提取區(qū)間。

。。。。。。。。。

還有一堆細節(jié)

。。。。。。。。。

?

放上代碼:

大概4+4+4=12種討論?

刪掉注釋250行左右

#include<bits/stdc++.h> #define reg register int #define il inline #define ls t[x].ch[0] #define rs t[x].ch[1] #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); } namespace Miracle{ const int N=100000+5; const int nd=3; const int st=1; int n; struct node{int l,r,v;int fa,ch[2];int tag;node(){}node(int ll,int rr,int vv){l=ll,r=rr,v=vv;ch[0]=ch[1]=0;fa=0;tag=0;}void op(){cout<<" left "<<l<<" right "<<r<<" val "<<v<<endl;cout<<" father "<<fa<<" son1 "<<ch[0]<<" son2 "<<ch[1]<<" tag "<<tag<<endl;} }t[N]; int cnt; int rt; void tag(int x,int c){t[x].tag+=c;t[x].v+=c;t[x].l+=c;t[x].r+=c; } void pushdown(int x){if(!t[x].tag) return; // cout<<" pushdown "<<x<<" "<<t[x].tag<<endl; tag(ls,t[x].tag);tag(rs,t[x].tag);t[x].tag=0; } void rotate(int x){int y=t[x].fa,d=t[y].ch[1]==x;t[t[y].ch[d]=t[x].ch[!d]].fa=y;t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;t[t[x].ch[!d]=y].fa=x; } void splay(int x,int f){while(t[x].fa!=f){int y=t[x].fa,z=t[y].fa;if(z!=f){rotate((t[z].ch[0]==y)&&(t[y].ch[0]==x)?y:x);}rotate(x);}if(f==0) rt=x; } int pre(int x){splay(x,0);x=t[x].ch[0];if(!x) return -1;pushdown(x);while(t[x].ch[1]) {x=t[x].ch[1];pushdown(x);}return x; } int bac(int x){ // cout<<" fin bac "<<x<<" "<<t[x].ch[0]<<endl;splay(x,0);x=t[x].ch[1]; // cout<<" ch[1] "<<x<<" "<<t[x].ch[0]<<endl;if(!x) return -1;pushdown(x);while(t[x].ch[0]) {x=t[x].ch[0];pushdown(x);}return x; } int kth(int k){ // cout<<" find kth "<<k<<endl;int x=rt;while(x){pushdown(x);// cout<<" xx "<<x<<endl;t[x].op();if(t[x].l<=k&&k<=t[x].r) return x;else if(t[x].l>k) x=t[x].ch[0];else if(t[x].r<k) x=t[x].ch[1];}return -1;//warning !!! } void merge(int x,int y){//cout<<" merge "<<x<<" "<<y<<endl;splay(x,0);splay(y,x);t[t[x].ch[1]=t[y].ch[1]].fa=x;t[x].r=t[y].r; } void split(int x,int l,int r){++cnt;t[cnt]=node(l,r,t[x].v);t[t[cnt].ch[1]=t[x].ch[1]].fa=cnt;t[cnt].fa=x;t[x].ch[1]=cnt;t[x].r=l-1;//warning!! } void wrk(int L,int R){ // cout<<" wrking ---------------------"<<L<<" "<<R<<endl;int lc=kth(L),rc=kth(R);//cout<<" lc "<<lc<<endl;t[lc].op();//cout<<" rc "<<rc<<endl;t[rc].op();if(lc==rc){// cout<<" Sol 1*****"<<endl;if(L==R){// cout<<" 1.1%%"<<endl;if(t[lc].l==L){ // int pr=pre(lc); // if(pr==st){ // int bc=bac(lc); // if(bc==nd){ // ++t[lc].v; // }else{ // merge(lc,bc); // // } // }return;}else if(t[lc].r==L){int bc=bac(lc);if(bc==nd){//las cur split(lc,L,R);++t[cnt].v;}else{t[bc].l=L;t[lc].r=L-1;}return;}else{//cout<<" 1.1.3$$$ "<<endl;int bc=bac(lc);// cout<<" bc "<<bc<<endl;if(bc==nd){split(lc,L,t[lc].r);++t[cnt].v;}else{t[bc].l=L;t[lc].r=L-1;}return;}}else{if(t[lc].l==L){int bc=bac(lc);if(bc==nd){//las cursplit(lc,t[lc].l+1,t[lc].r);++t[cnt].v;}else{t[bc].l=t[lc].l+1;t[lc].r=t[lc].l;}return;}else{int bc=bac(lc);if(bc==nd){//las cur split(lc,L,t[lc].r);++t[cnt].v;}else{t[bc].l=L;t[lc].r=L-1;}return;}}return;}int pr=pre(rc);if(pr==lc){if(t[lc].l==L&&t[rc].l==R){t[lc].r=L;t[rc].l=L+1;}else if(t[lc].l==L){int bc=bac(rc);if(bc==nd){split(rc,t[rc].l+1,t[rc].r);++t[cnt].v;}else{t[bc].l=t[rc].l+1;t[rc].r=t[rc].l;}t[rc].l=L+1;t[lc].r=L;}else if(t[rc].l==R){t[rc].l=L;t[lc].r=L-1;}else{int bc=bac(rc);if(bc==nd){split(rc,t[rc].l+1,t[rc].r);++t[cnt].v;}else{t[bc].l=t[rc].l+1;t[rc].r=t[rc].l;}t[rc].l=L;t[lc].r=L-1;}}else{//cout<<" Sol 3*******"<<endl;if(t[rc].l==R){merge(pr,rc);rc=pr;t[rc].r--;}else{// cout<<" 3.1.2$$$"<<endl;int bc=bac(rc);// cout<<" bac "<<bc<<endl;if(bc==nd){t[rc].r--;}else{merge(rc,bc);t[rc].r--;}}if(t[lc].l==L){split(lc,L,t[lc].r);t[lc].r=L;lc=cnt;}else{split(lc,L-1,t[lc].r);t[lc].r=L-1;lc=cnt;}int LL=pre(lc),RR=bac(rc);splay(LL,0);splay(RR,LL);//cout<<" LL "<<LL<<endl;t[LL].op();// cout<<" RR "<<RR<<endl;t[RR].op();tag(t[RR].ch[0],1);} } int calc(){splay(nd,0);int cur=pre(nd);return t[cur].v; } int main(){rd(n);rt=1;t[++cnt]=node(-1,-1,0);t[cnt].fa=0;t[cnt].ch[1]=cnt+1;++cnt;t[cnt]=node(0,n,0);t[cnt].fa=1;t[cnt].ch[1]=cnt+1;++cnt;t[cnt]=node(n+1,n+1,0);t[cnt].fa=2;// cout<<t[1].fa<<" "<<t[1].ch[0]<<" "<<t[1].ch[1]<<endl; // cout<<t[2].fa<<" "<<t[2].ch[0]<<" "<<t[2].ch[1]<<endl; // cout<<t[3].fa<<" "<<t[3].ch[0]<<" "<<t[3].ch[1]<<endl;int L,R;for(reg i=1;i<=n;++i){rd(L);rd(R);wrk(L,R);// cout<<" after wrk "<<cnt<<endl; }printf("%d\n",calc());return 0; }} signed main(){Miracle::main();return 0; }/*Author: *Miracle*Date: 2018/12/24 13:54:20 */ View Code

?

太TMD麻煩了。。。。。(要不是為了鍛煉碼力才不寫)

發(fā)現(xiàn)之前的方法麻煩的地方在于,維護[l,r]這個區(qū)間要來回討論。函數(shù)值+1要討論。左端點要討論。split,merge要討論。。。

落差都是1,怎么利用呢?

用一些點來維護分段函數(shù)!

每個點表示這個分段函數(shù)的左端點。維護點的橫坐標

修改的時候,

[l,r)的左端點集體右移,加入一個l點,把>=r最小的點刪除。沒了。

原因是,我們不記錄高度,一個函數(shù)值左邊的點的個數(shù),就是函數(shù)值的大小!

所以,插入一個點相當于對后面的所有點高度+1,只需要將點向右平移。

同時,代替合并函數(shù)值的是,把>=r的點刪除掉。

一個關(guān)鍵點在r的位置,并不能+1,所以是開區(qū)間。

最后點的個數(shù)就是函數(shù)值!

?

?

總結(jié):

1.DP首先要想到。觀察轉(zhuǎn)移,得到分段函數(shù)的性質(zhì)

2.分段函數(shù)的移動,可以模式化,所以可以打標記。

3.平衡樹維護分段函數(shù),以及一些小技巧。

?

轉(zhuǎn)載于:https://www.cnblogs.com/Miracevin/p/10171156.html

總結(jié)

以上是生活随笔為你收集整理的模拟赛 yjqb的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。