线段树合并与分裂
http://blog.csdn.net/zawedx/article/details/51818475
由于上面这篇文章讲的很清楚了,不打算再讲一遍......骗访问量也要按基本法
利用这种动态开点的值域线段树可以解决一堆有序集合进行合并/分裂/查询k小的问题,最好用的就是在排序问题中。
例1 bzoj4552
m次排序,每次对一个区间升序或降序排序,最后询问一个位置的值。
有一种比较咸鱼的做法是二分答案然后转化为01序列来做,这里就不说了= =
我们可以把排序好的一坨当做一个有序集合,用一个set维护一下这些集合的起止端点,然后排序的时候只要把这些集合全部并在一起就行了。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back #define mp make_pair typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e]) #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");} #define VIZ2 {printf("graph G{\n"); for(int i=1;i<=n;i++) for es(i,e) if(vb[e]>=i)printf("%d--%d;\n",i,vb[e]); puts("}");} #define SZ 666666 #define SG 9999999 //merge-split seg begin int ss[SG],sn=0,ch[SG][2],s[SG]; #define er(x) ss[++sn]=x inline int alc_() { int x=ss[sn--]; ch[x][0]=ch[x][1]=s[x]=0; return x; } #define alc alc_() //make a seg with only node p void build(int& x,int l,int r,int p) { x=alc; s[x]=1; //cout<<"build"<<x<<","<<l<<","<<r<<','<<p<<"\n"; if(l==r) return; int m=(l+r)>>1; if(p<=m) build(ch[x][0],l,m,p); else build(ch[x][1],m+1,r,p); } //merge t1&t2 int merge(int t1,int t2) { if(t1&&t2);else return t1^t2; ch[t1][0]=merge(ch[t1][0],ch[t2][0]); ch[t1][1]=merge(ch[t1][1],ch[t2][1]); s[t1]+=s[t2]; er(t2); return t1; } //split t1 to t1&t2 so that s[t1]=k void split(int t1,int&t2,int k) { t2=alc; int ls=s[ch[t1][0]]; if(k>ls) split(ch[t1][1],ch[t2][1],k-ls); else swap(ch[t1][1],ch[t2][1]); if(k<ls) split(ch[t1][0],ch[t2][0],k); s[t2]=s[t1]-k; s[t1]=k; } int ask(int x,int l,int r,int k) { if(l==r) return l; int ls=s[ch[x][0]]; int m=(l+r)>>1; if(k>ls) return ask(ch[x][1],m+1,r,k-ls); return ask(ch[x][0],l,m,k); } void ps(int x,int l,int r,int dep=0) { if(!x) return; for(int i=1;i<=dep;i++) putchar(' '); cout<<x<<" "<<s[x]<<" "<<l<<","<<r<<" lc"<<ch[x][0]<<"rc"<<ch[x][1]<<"\n"; ps(ch[x][0],l,(l+r)>>1,dep+1); ps(ch[x][1],(l+r)/2+1,r,dep+1); } //seg end bool typ[SZ]; //0< 1> int rots[SZ],rs[SZ]; //i pos store l=i set<int> sol; int n,q,a[SZ]; //split x so that rs[x]=s void sp(int x,int s) { //cout<<"split"<<x<<","<<s<<"\n"; if(s>=rs[x]||s<x) return; if(!typ[x]) split(rots[x],rots[s+1],s-x+1); else { rots[s+1]=rots[x]; split(rots[s+1],rots[x],rs[x]-s); } rs[s+1]=rs[x]; rs[x]=s; sol.insert(s+1); typ[s+1]=typ[x]; } //it's your task to edit typ[a]! void mg(int a,int b) { //cout<<"mg"<<a<<","<<b<<"\n"; if(a==b) return; sol.erase(b); rots[a]=merge(rots[a],rots[b]); rs[a]=rs[b]; //cout<<a<<","<<rs[a]<<"\n"; } int qpos(int x,int k) { k-=x-1; if(!typ[x]) return ask(rots[x],1,n,k); else return ask(rots[x],1,n,rs[x]-x+2-k); } void dbg() { cout<<sol.size()<<"\n"; for(set<int>::iterator g=sol.begin();g!=sol.end();g++) { cout<<*g<<" "<<rs[*g]<<" "<<typ[*g]<<"\n"; ps(rots[*g],1,n); } } #define ch ____ch char ch,B[1<<15],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++) #define isd(c) (c>='0'&&c<='9') int aa,bb;int F(){ while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1); while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa; } #define gi F() int main() { for(int i=SG-1;i>=1;i--) ss[++sn]=i; //scanf("%d%d",&n,&q); n=gi, q=gi; for(int i=1;i<=n;i++) { a[i]=gi; //scanf("%d",a+i); build(rots[i],1,n,a[i]); sol.insert(i); rs[i]=i; } static int tmp[SZ],tn=0; while(q--) { int o=gi,l=gi,r=gi; //scanf("%d%d%d",&o,&l,&r); { set<int>::iterator w=sol.upper_bound(l); sp(*(--w),l-1); w=sol.upper_bound(r); sp(*(--w),r); } set<int>::iterator p1=sol.lower_bound(l), p2=sol.upper_bound(r); --p2; int tg=*p1; if(p1!=p2) { for(set<int>::iterator i=++p1;;++i) { tmp[++tn]=*i; if(i==p2) break; } for(int i=1;i<=tn;i++) mg(tg,tmp[i]); tn=0; } typ[tg]=o; } int r=gi; set<int>::iterator w=sol.upper_bound(r); int x=*(--w); printf("%d\n",qpos(x,r)); }
例2 yzoj2753
问题可以被当做是把序列中的一段进行升序/降序排序或者交换两个元素。
同样可以咸鱼一点二分答案之后做,不过这也不是重点...
做法和上一题差不多。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back #define mp make_pair typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e]) #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");} #define VIZ2 {printf("graph G{\n"); for(int i=1;i<=n;i++) for es(i,e) if(vb[e]>=i)printf("%d--%d;\n",i,vb[e]); puts("}");} #define SZ 666666 #define SG 7777777 //merge-split seg begin int ss[SG],sn=0,ch[SG][2],s[SG]; #define er(x) ss[++sn]=x inline int alc_() { int x=ss[sn--]; ch[x][0]=ch[x][1]=0;//s[x]=0; return x; } #define alc alc_() //make a seg with only node p void build(int& x,int l,int r,int p) { x=alc; s[x]=1; if(l==r) return; int m=(l+r)>>1; if(p<=m) build(ch[x][0],l,m,p); else build(ch[x][1],m+1,r,p); } //merge t1&t2 int merge(int t1,int t2) { if(t1&&t2);else return t1^t2; ch[t1][0]=merge(ch[t1][0],ch[t2][0]); ch[t1][1]=merge(ch[t1][1],ch[t2][1]); s[t1]+=s[t2]; er(t2); return t1; } //split t1 to t1&t2 so that s[t1]=k void split(int t1,int&t2,int k) { t2=alc; if(ch[t1][0]||ch[t1][1]) { int ls=s[ch[t1][0]]; if(k>ls) split(ch[t1][1],ch[t2][1],k-ls); else swap(ch[t1][1],ch[t2][1]); if(k<ls) split(ch[t1][0],ch[t2][0],k); } s[t2]=s[t1]-k; s[t1]=k; } int ask(int x,int l,int r,int k) { if(l==r) return l; int ls=s[ch[x][0]]; int m=(l+r)>>1; if(k>ls) return ask(ch[x][1],m+1,r,k-ls); return ask(ch[x][0],l,m,k); } //seg end typedef set<int> Set; int R=1e9; Set sol; bool typ[SZ]; //0< 1> int rots[SZ],rs[SZ]; //i pos store l=i int n,q,a[SZ]; //split x so that rs[x]=s void sp(int x,int s) { if(s>=rs[x]||s<x) return; if(!typ[x]) split(rots[x],rots[s+1],s-x+1); else { rots[s+1]=rots[x]; split(rots[s+1],rots[x],rs[x]-s); } rs[s+1]=rs[x]; rs[x]=s; sol.insert(s+1); typ[s+1]=typ[x]; } //it's your task to edit typ[a]! void mg(int a,int b) { if(a==b) return; sol.erase(b); rots[a]=merge(rots[a],rots[b]); rs[a]=rs[b]; } int qpos(int x,int k) { k-=x-1; if(!typ[x]) return ask(rots[x],0,R,k); else return ask(rots[x],0,R,rs[x]-x+2-k); } #define fpos my_fpos int fpos(int x) { Set::iterator w=sol.upper_bound(x); return *(--w); } #define ch reader_ch char ch,B[1<<15],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++) #define isd(c) (c>='0'&&c<='9') int aa,bb;int F(){ while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1); while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa; } #define gi F() void sort(int l,int r,int o) { if(l==r) return; static int tmp[SZ],tn=0; sp(fpos(l),l-1); sp(fpos(r),r); Set::iterator p1=sol.lower_bound(l), p2=sol.upper_bound(r); --p2; int tg=*p1; if(p1!=p2) { for(Set::iterator i=++p1;;++i) { tmp[++tn]=*i; if(i==p2) break; } for(int i=1;i<=tn;i++) mg(tg,tmp[i]); tn=0; } typ[tg]=o; } void qwq() { sol.clear(); sn=R=0; for(int i=SG-1;i>=1;i--) ss[++sn]=i; n=gi, q=gi; for(int i=1;i<=n+n;i++) R=max(R,a[i]=gi); for(int i=1;i<=n+n;i++) { build(rots[i],0,R,a[i]); sol.insert(i); rs[i]=i; } while(q--) { int o=gi,a=gi,b=gi,c=gi,d=gi; if(o==1) { int p=a*n+b,q=a*n+c; sort(p,q,d); } else { int p=a*n+b,q=c*n+d; sp(fpos(p),p-1); sp(fpos(p),p); sp(fpos(q),q-1); sp(fpos(q),q); swap(rots[p],rots[q]); } } int x_=gi,y_=gi,x=x_*n+y_; printf("%d\n",qpos(fpos(x),x)); } int main() { int T=gi; while(T--) qwq(); }
于是好好的安利文就成了贴板子= =如果有比较有趣的题再更新吧
另外不是很懂splay和treap要怎么搞这个东西啊