您的位置:首页 > 其它

[bzoj3123][SDOI2013]森林

2016-07-01 12:47 429 查看

Description

给出一片森林,要求维护以下操作。

Q x,y,k 询问x到y的路径上权值第k小的是什么。

L x,y 在x,y之间连一条边,保证操作之后原图仍是一片森林。

强制在线。

n<=8*10^4,权值<=10^9

Solution

看到求k小值,立马想到主席树。(Chair_Man Tree大法好)

那么询问操作很简单。

那么合并呢?

启发式合并!

也就是选择要合并的两棵树中较小的那一棵塞到较大的那一棵里面去。

这样做的复杂度是均摊O(nlogn)的。(不要问为什么)

然后加上个离散化省点空间。

然后就没有了。(启发式合并是个好东西,(⊙v⊙)嗯)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 80005
using namespace std;
struct tree{int l,r,size;}tr[N*300];
struct note{int v,w;}a
;
bool cmp(note x,note y) {return x.v<y.v;}
int n,m,q,ty,l,x,y,k,tot,cnt,ans,size
,root
,f
[17];
int last
,next[N*2],t[N*2],rt
,c
,d
,h
;
char ch[1];
void add(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
void change(int &v,int l,int r,int x) {
tr[++tot]=tr[v];tr[tot].size++;v=tot;
if (l==r) return;
int m=(l+r)/2;
if (x<=m) change(tr[v].l,l,m,x);
else change(tr[v].r,m+1,r,x);
}
void dfs(int x,int y) {
root[x]=root[y];
change(root[x],1,cnt,c[x]);
f[x][0]=y;d[x]=d[y]+1;size[x]=1;
fo(j,1,16) f[x][j]=f[f[x][j-1]][j-1];
rep(i,x) if (t[i]!=y) dfs(t[i],x),size[x]+=size[t[i]];
}
void make(int x,int y,int z) {
size[x]=y;rt[x]=z;
rep(i,x) if (t[i]!=f[x][0]) make(t[i],y,z);
}
int lca(int x,int y) {
if (d[x]<d[y]) swap(x,y);
fd(j,16,0) if (d[f[x][j]]>d[y]) x=f[x][j];
if (d[x]!=d[y]) x=f[x][0];
fd(j,16,0) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
if (x!=y) return f[x][0];else return x;
}
int find(int x,int y,int z,int f,int l,int r,int id) {
if (l==r) return l;
int m=(l+r)/2;
int lx=tr[x].l,rx=tr[x].r;
int ly=tr[y].l,ry=tr[y].r;
int lz=tr[z].l,rz=tr[z].r;
int lf=tr[f].l,rf=tr[f].r;
if (tr[lx].size+tr[ly].size-tr[lz].size-tr[lf].size>=id)
return find(lx,ly,lz,lf,l,m,id);else
return find(rx,ry,rz,rf,m+1,r,id-tr[lx].size-tr[ly].size+tr[lz].size+tr[lf].size);
}
void merge(int x,int y) {
add(x,y);add(y,x);
if (size[x]>size[y]) swap(x,y);
dfs(x,y);make(rt[y],size[x]+size[y],rt[y]);
}
int main() {
scanf("%d%d%d%d",&n,&n,&m,&q);
fo(i,1,n) scanf("%d",&a[i].v),a[i].w=i;
sort(a+1,a+n+1,cmp);
fo(i,1,n) {
if (a[i].v!=a[i-1].v) h[++cnt]=a[i].v;
c[a[i].w]=cnt;
}
fo(i,1,m) scanf("%d%d",&x,&y),add(x,y),add(y,x);
fo(i,1,n) if (!root[i]) dfs(i,0),make(i,size[i],i);
for(;q;q--) {
scanf("%s%d%d",ch,&x,&y);x^=ans;y^=ans;
if (ch[0]=='Q') {
int z=lca(x,y);scanf("%d",&k);k^=ans;
ans=h[find(root[x],root[y],root[z],root[f[z][0]],1,cnt,k)];
printf("%d\n",ans);
} else merge(x,y);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: