bzoj 2733: [HNOI2012]永無鄉【並查集+權值線段樹】
阿新 • • 發佈:2018-09-24
pri 權值線段樹 bzoj date sca scan %s 線段 struct
bzoj上數組開大會T……
本來想用set瞎搞的,想了想發現不行
總之就是並查集,每個點開一個動態開點的權值線段樹,然後合並的時候把值並在根上,詢問的時候找出在根的線段樹裏找出k小值,看看這個值屬於哪個島即可
#include<iostream> #include<cstdio> using namespace std; const int N=100005; int n,m,q,f[N],rt[N],tot,rl[N]; char c[5]; struct qwe { int ls,rs,s; }t[10000005]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } int zhao(int x) { return f[x]==x?x:f[x]=zhao(f[x]); } void ud(int ro) { t[ro].s=t[t[ro].ls].s+t[t[ro].rs].s; } void update(int &ro,int l,int r,int p) { if(!ro) ro=++tot; if(l==r) { t[ro].s=1; return; } int mid=(l+r)>>1; if(p<=mid) update(t[ro].ls,l,mid,p); else update(t[ro].rs,mid+1,r,p); ud(ro); } void hb(int &ro,int la,int l,int r) { if(!la) return; if(!ro) { ro=la; return; } if(l==r) { t[ro].s+=t[la].s; return ; } int mid=(l+r)>>1; hb(t[ro].ls,t[la].ls,l,mid); hb(t[ro].rs,t[la].rs,mid+1,r); ud(ro); } int ques(int ro,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; if(t[ro].ls&&t[t[ro].ls].s>=k) return ques(t[ro].ls,l,mid,k); else return ques(t[ro].rs,mid+1,r,k-t[t[ro].ls].s); } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { f[i]=i; int x=read(); rl[x]=i; update(rt[i],1,n,x); } for(int i=1;i<=m;i++) { int x=read(),y=read(),fx=zhao(x),fy=zhao(y); if(fx!=fy) { f[fy]=fx; hb(rt[fx],rt[fy],1,n); } } q=read(); while(q--) { scanf("%s",c); int x=read(),y=read(); if(c[0]==‘B‘) { int fx=zhao(x),fy=zhao(y); if(fx!=fy) { f[fy]=fx; hb(rt[fx],rt[fy],1,n); } } else { int fx=zhao(x); if(t[rt[fx]].s<y) puts("-1"); else printf("%d\n",rl[ques(rt[fx],1,n,y)]); } } return 0; }
bzoj 2733: [HNOI2012]永無鄉【並查集+權值線段樹】