BZOJ3123:[SDOI2013]森林——题解
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3123:[SDOI2013]森林——题解相关的知识,希望对你有一定的参考价值。
http://www.lydsy.com/JudgeOnline/problem.php?id=3123
https://www.luogu.org/problemnew/show/P3302
树上主席树操作方法看:http://www.cnblogs.com/luyouqi233/p/8159528.html
这题要动态树,显然不可能LCT套主席树啊。
那我们完全可以启发式合并一下主席树。
剩下的操作就很简单了。
(然而我debug两个小时才发现我n定义了两个emmmm)
#include<cstdio> #include<cmath> #include<cstring> #include<cctype> #include<iostream> #include<algorithm> using namespace std; const int N=8e4+10; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==\'-\';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct tree{ int l,r,sum; }tr[N*500]; struct node{ int to,nxt; }edge[N*2]; int a[N],b[N],rt[N],pool,n,m; int dep[N],anc[N][20],son[N]; int cnt,head[N],fa[N],vis[N],tot; inline void add(int u,int v){ edge[++cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt; } inline void insert(int y,int &x,int l,int r,int p){ tr[x=++pool]=tr[y];tr[x].sum++; if(l==r)return; int mid=(l+r)>>1; if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p); else insert(tr[y].r,tr[x].r,mid+1,r,p); } inline int query(int nl,int nr,int nm,int nfm,int l,int r,int k){ if(l==r)return l; int delta=tr[tr[nl].l].sum+tr[tr[nr].l].sum-tr[tr[nm].l].sum-tr[tr[nfm].l].sum; int mid=(l+r)>>1; if(delta>=k)return query(tr[nl].l,tr[nr].l,tr[nm].l,tr[nfm].l,l,mid,k); else return query(tr[nl].r,tr[nr].r,tr[nm].r,tr[nfm].r,mid+1,r,k-delta); } inline void LSH(){ sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1; for(int i=1;i<=n;i++){ a[i]=lower_bound(b+1,b+m+1,a[i])-b; } return; } inline int LCA(int i,int j){ if(dep[i]<dep[j])swap(i,j); for(int k=16;k>=0;k--){ if(dep[anc[i][k]]>=dep[j])i=anc[i][k]; } if(i==j)return i; for(int k=16;k>=0;k--){ if(anc[i][k]!=anc[j][k])i=anc[i][k],j=anc[j][k]; } return anc[i][0]; } int find(int x){ if(fa[x]==x)return x; return fa[x]=find(fa[x]); } void dfs(int u,int f,int root){ anc[u][0]=f; for(int k=1;k<=16;k++) anc[u][k]=anc[anc[u][k-1]][k-1]; son[root]++;dep[u]=dep[f]+1;fa[u]=root;vis[u]=1; insert(rt[f],rt[u],1,m,a[u]); for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v!=f)dfs(v,u,root); } return; } int main(){ read(); n=read();int e=read(),T=read(),last=0; for(int i=1;i<=n;i++) a[i]=b[++m]=read(),fa[i]=i; LSH(); for(int i=1;i<=e;i++){ int x=read(),y=read(); add(x,y);add(y,x); } for(int i=1;i<=n;i++) if(!vis[i]){ dfs(i,0,++tot);fa[tot]=tot; } for(int i=1;i<=T;i++){ char ch=getchar(); while(ch!=\'Q\'&&ch!=\'L\')ch=getchar(); if(ch==\'Q\'){ int x=read()^last,y=read()^last,k=read()^last; int t=LCA(x,y),ft=anc[t][0]; printf("%d\\n",last=b[query(rt[x],rt[y],rt[t],rt[ft],1,m,k)]); }else{ int x=read()^last,y=read()^last; add(x,y);add(y,x); int u=find(x),v=find(y); if(son[u]<son[v]){ swap(u,v); swap(x,y); } dfs(y,x,u); } } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
以上是关于BZOJ3123:[SDOI2013]森林——题解的主要内容,如果未能解决你的问题,请参考以下文章
主席树 启发式合并bzoj3123: [Sdoi2013]森林