BZOJ 3123: [Sdoi2013]森林|主席树|启发式合并
2016-02-20 14:59
573 查看
做法和2588一模一样,只不过多了个合并操作,所谓的启发式合并,就是永远都把小的往大的上合并,然后合并的时候暴力就行了.
因为查询的时候忘记减去左区间的数量,RE的根本停不下来….
因为查询的时候忘记减去左区间的数量,RE的根本停不下来….
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<set> #include<map> #include<iostream> #include<algorithm> #define ll unsigned long long #define N 100022 #define mx 1e9 using namespace std; int sc() { int i=0,f=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i*f; } int head ,nxt[N*2],lst[N*2],size ,fa [20],v ,deep ; int ch[N*400][2],sum[N*400],root ; int n,m,cnt,t,tot,ans; void insert(int x,int y) { lst[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } int find(int x) { while(fa[x][0])x=fa[x][0]; return x; } void add(int pre,int &x,int l,int r,int v) { if(!x)x=++cnt; sum[x]=sum[pre]+1; if(l==r)return; int mid=l+r>>1; if(v>mid) ch[x][0]=ch[pre][0], add(ch[pre][1],ch[x][1],mid+1,r,v); else ch[x][1]=ch[pre][1], add(ch[pre][0],ch[x][0],l,mid,v); } void dfs(int x,int f) { fa[x][0]=f;root[x]=0; size[x]=1;deep[x]=deep[f]+1; add(root[f],root[x],1,mx,v[x]); for(int i=1;i<17;i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=head[x];i;i=nxt[i]) if(lst[i]!=f) { dfs(lst[i],x); size[x]+=size[lst[i]]; } } int Lca(int x,int y) { if(deep[x]<deep[y])swap(x,y); int t=deep[x]-deep[y]; for(int i=0;i<17;i++) if(t&(1<<i))x=fa[x][i]; for(int i=16;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y?y:fa[x][0]; } int ask(int x,int y,int k) { int z=Lca(x,y),a=root[x],b=root[y],c=root[z]; int l=1,r=mx,w=v[z]; while(l!=r) { int mid=l+r>>1; int lsum=sum[ch[a][0]]+sum[ch[b][0]]-2*sum[ch[c][0]]+(w>=l&&w<=mid); bool e=k>lsum; e?l=mid+1,k-=lsum:r=mid;//!!!!!!!!!!!!!!!!! a=ch[a][e],b=ch[b][e],c=ch[c][e]; } return l; } int main() { int Q=sc(); n=sc(),m=sc(),t=sc(); for(int i=1;i<=n;i++) v[i]=sc(), fa[i][0]=0; for(int i=1;i<=m;i++) { int x=sc(),y=sc(); insert(x,y); insert(y,x); } for(int i=1;i<=n;i++) if(!fa[i][0])dfs(i,0); for(int i=1;i<=t;i++) { char s[10];scanf("%s",s); if(s[0]=='L') { int x=sc()^ans,y=sc()^ans; int fx=find(x),fy=find(y); if(size[fx]<size[fy])swap(fx,fy),swap(x,y); size[fx]+=size[fy]; insert(x,y),insert(y,x); dfs(y,x); } else { int x=sc()^ans,y=sc()^ans,k=sc()^ans; printf("%d\n",ans=ask(x,y,k)); } } return 0; }
相关文章推荐
- [BZOJ2006][NOI2010][RMQ/主席树][二叉堆]超级钢琴
- BZOJ 2588 Count On a Tree 【LCA】【主席树】
- 主席树(可持久化线段树)入门专题
- BZOJ3209 花神的嘲讽计划I
- POJ 2104 K-th Number
- SPOJ COT 10628 Count on a tree
- ZOJ 2112 Dynamic Rankings
- HDU 4417 Super Mario
- HDU 4348 To the moon
- Codeforces 587C Duff in the Army
- bzoj-3123 森林
- poj 2104 K-th Number (主席树学习第一弹)
- hdu 4605 Magic Ball Game(主席树学习第二弹)
- hdu 4866 Shooting(主席树学习第三弹)
- hdu 3727 Jewel(主席树学习第四弹)
- 【Poi2014】【BZOJ3524】Couriers
- 【BZOJ4209】西瓜王
- SPOJ 10628 Count on The tree .. .. 主席树
- 主席树-区间第k大值(不带修改)
- hdu4417 Super Mario (主席树+二分)