您的位置:首页 > 其它

bzoj3123 森林 主席树&启发式合并

2016-02-15 19:58 316 查看
如果没有Link操作就是裸的主席树。

如果有Link操作,就每次把小的往大的并,每个点最多并logN次,每次logN,因此总的时间复杂度O(Nlog^2N),空间复杂度O(Nlog^2N),如果加上垃圾回收就是O(NlogN)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 80005
#define M 20000005
using namespace std;

int n,m,ps,tot,cnt,trtot,fst
,pnt[N<<1],nxt[N<<1],a
,num
,hash
,d
;
int rt
,ls[M],rs[M],sum[M],fa
[17],father
,mi2[20],val
;
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
void add(int aa,int bb){
pnt[++tot]=bb; nxt[tot]=fst[aa]; fst[aa]=tot;
}
int find(int x){
int l=1,r=cnt,mid;
while (l<r){
mid=(l+r)>>1; if (hash[mid]<x) l=mid+1; else r=mid;
}
return l;
}
int lca(int x,int y){
if (d[x]<d[y]) swap(x,y); int i,tmp=d[x]-d[y];
for (i=0; i<=16; i++) if (tmp&mi2[i]) x=fa[x][i];
for (i=16; i>=0; i--)
if (fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; }
return (x==y)?x:fa[x][0];
}
void ins(int l,int r,int x,int &y,int k){
y=++trtot; sum[y]=sum[x]+1;
if (l==r) return; int mid=(l+r)>>1;
if (k<=mid){ rs[y]=rs[x]; ins(l,mid,ls[x],ls[y],k); }
else{ ls[y]=ls[x]; ins(mid+1,r,rs[x],rs[y],k); }
}
int qry(int x,int y,int k){
int u=lca(x,y),v=fa[u][0],l=1,r=cnt,mid;
x=rt[x]; y=rt[y]; u=rt[u]; v=rt[v];
while (l<r){
mid=(l+r)>>1; int tmp=sum[ls[x]]+sum[ls[y]]-sum[ls[u]]-sum[ls[v]];
if (tmp>=k){ x=ls[x]; y=ls[y]; u=ls[u]; v=ls[v]; r=mid; }
else{ k-=tmp; x=rs[x]; y=rs[y]; u=rs[u]; v=rs[v]; l=mid+1; }
}
return hash[l];
}
void dfs(int x,int last){
d[x]=d[last]+1; fa[x][0]=last; int p,i;
for (i=1; i<=16; i++) fa[x][i]=fa[fa[x][i-1]][i-1];
ins(1,cnt,rt[last],rt[x],a[x]);
for (p=fst[x]; p; p=nxt[p]) if (pnt[p]!=last) dfs(pnt[p],x);
}
int getfa(int x){ return (x==father[x])?x:getfa(father[x]); }
void link(int x,int y){
int u=getfa(x),v=getfa(y);
if (val[u]>val[v]){ swap(x,y); swap(u,v); }
val[v]+=val[u]; father[u]=v;
add(x,y); add(y,x); dfs(x,y);
}
int main(){
int cas=read(),i; mi2[0]=1; for (i=1; i<=17; i++) mi2[i]=mi2[i-1]<<1;
n=read(); m=read(); ps=read();
for (i=1; i<=n; i++) a[i]=num[i]=read();
sort(num+1,num+n+1);
for (i=1; i<=n; i++)
if (i==1 || num[i]!=num[i-1]) hash[++cnt]=num[i];
for (i=1; i<=n; i++) a[i]=find(a[i]);
for (i=1; i<=n; i++){ val[i]=1; father[i]=i; }
for (i=1; i<=m; i++){
int x=read(),y=read(); link(x,y);
}
for (i=1; i<=n; i++) if (!d[i]) dfs(i,0);
int ans=0; char ch;
while (ps--){
ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar();
if (ch=='Q'){
int x=read()^ans,y=read()^ans,z=read()^ans;
printf("%d\n",ans=qry(x,y,z));
} else{
int x=read()^ans,y=read()^ans; link(x,y);
}
}
return 0;
}


by lych
2016.2.15
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: