bzoj2733 / P3224 [HNOI2012]永无乡(并查集+线段树合并)
每个联通块的点集用动态开点线段树维护
并查集维护图
合并时把线段树也合并就好了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cctype> 5 #define re register 6 #define gc getchar 7 using namespace std; 8 void chread(char &x){ 9 char c=gc(); 10 while(!isupper(c)) c=gc(); 11 x=c; 12 } 13 void read(int &x){ 14 char c=gc();x=0; bool f=1; 15 while(!isdigit(c)) f=(f&&c!='-'),c=gc(); 16 while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=gc(); 17 x=f?x:-x; 18 } 19 void swap(int &a,int &b){a^=b;b^=a;a^=b;} 20 #define N 100002 21 #define M 600002 22 struct edge{int u,v;bool del;}b[M]; 23 struct node{ 24 int sum,lc,rc; 25 }c[M<<2]; 26 int n,m,t,u,val[N],fa[N],rt[N],ttp,id[N]; 27 double ans; 28 29 void update(int &o,int l,int r,int v,int k){//插入 30 if(!o) o=++u; 31 if(l==r) {c[o].sum+=k; return;} 32 int mid=l+((r-l)>>1); 33 if(v<=mid) update(c[o].lc,l,mid,v,k); 34 else update(c[o].rc,mid+1,r,v,k); 35 c[o].sum=c[c[o].lc].sum+c[c[o].rc].sum; 36 } 37 void merge(int &o,int pr){//合并 38 if(!o||!pr) {o+=pr;return;} 39 c[o].sum+=c[pr].sum; 40 merge(c[o].lc,c[pr].lc); 41 merge(c[o].rc,c[pr].rc); 42 } 43 int query(int o,int l,int r,int k){//询问 44 if(l==r) return l; 45 int mid=l+((r-l)>>1); 46 if(k<=c[c[o].lc].sum) return query(c[o].lc,l,mid,k); 47 else return query(c[o].rc,mid+1,r,k-c[c[o].lc].sum); 48 } 49 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 50 void uni(int x,int y){//并查集合并 51 int r1=find(x),r2=find(y); 52 if(r1!=r2){ 53 merge(rt[r1],rt[r2]); 54 fa[r2]=r1; 55 } 56 } 57 int ask(int x,int k){ 58 int ffa=find(x); 59 return k>c[rt[ffa]].sum ?-1:id[query(rt[ffa],1,n,k)]; 60 } 61 int main(){ 62 char opt; int q1,q2; 63 read(n); read(m); 64 for(re int i=1;i<=n;++i){ 65 read(val[i]),id[val[i]]=i,fa[i]=i; 66 update(rt[i],1,n,val[i],1); 67 } 68 for(re int i=1;i<=m;++i) read(q1),read(q2),uni(q1,q2); 69 read(t); 70 for(re int i=1;i<=t;++i){ 71 chread(opt); read(q1); read(q2); 72 switch(opt){ 73 case 'B':{uni(q1,q2); break;} 74 case 'Q':{printf("%d\n",ask(q1,q2)); break;} 75 } 76 } 77 return 0; 78 }