题意:
给出一个n个点m条边的森林,每个点有一个点权,有两种操作;
1.查询两点之间的第K小的点权,保证合法;
2.连边(x,y);
m<n<=80000;
题解:
论正确姿势的重要性;
首先询问和某道COT的题很像,而这道题中多了Link操作;
然而,那道COT的题我是用树链剖分写的。。。
一开始的脑洞是每次将小的暴力重构作为一个轻链连在大的树上,然后每隔一段时间重构一次大树;
听起来十分暴力了。。鬼知道能不能过;
而正解是COT的正解的姿势,将一个询问分成四个,利用主席树的可减性质,找到LCA然后+x+y-LCA(x,y)-FA(LCA(x,y))像这样处理就可以了;
重构是差不多的,也是启发式合并,维护一下倍增LCA;
注意倍增LCA的数组要清。。小心RE,还是说那么写LCA的只有我一个= =?
空间给的足够的大,所以不需要写垃圾回收了,实际上因为每次重构的是整棵子树,回收是可以的但是有些麻烦。。;
总之还是一道挺好的题(笑);
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 81000 #define M 20002000 #define lson l,mid,ls[no] #define rson mid+1,r,rs[no] using namespace std; typedef long long ll; int next[N<<1],to[N<<1],head[N],ce; int val[N],dis[N],len; int deep[N],fa[N][22],root[N]; int size[M],ls[M],rs[M],tot; char op[10]; namespace Set { int size[N],f[N]; void init(int n) { for(int i=1;i<=n;i++) size[i]=1,f[i]=i; } int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } void Link(int x,int y) { x=find(x),y=find(y); if(x!=y) { if(size[x]>size[y]) swap(x,y); size[y]+=size[x]; f[x]=y; } } } int newnode() { static int ret; ret=++tot; ls[ret]=rs[ret]=size[ret]=0; return ret; } void Insert(int l,int r,int &no,int val) { int p=newnode(); ls[p]=ls[no],rs[p]=rs[no],size[p]=size[no]; no=p; size[no]++; if(l==r) return ; int mid=l+r>>1; if(val<=mid) Insert(lson,val); else Insert(rson,val); } int query(int l,int r,int no1,int no2,int no3,int no4,int k) { if(l==r) return l; else { int mid=l+r>>1; if(k<=size[ls[no1]]+size[ls[no2]]-size[ls[no3]]-size[ls[no4]]) return query(l,mid,ls[no1],ls[no2],ls[no3],ls[no4],k); else return query(mid+1,r,rs[no1],rs[no2],rs[no3],rs[no4], k-size[ls[no1]]-size[ls[no2]]+size[ls[no3]]+size[ls[no4]]); } } void dfs(int x) { deep[x]=deep[fa[x][0]]+1; root[x]=root[fa[x][0]]; Insert(1,len,root[x],val[x]); memset(fa[x]+1,0,sizeof(int)*21); for(int i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=head[x];i;i=next[i]) { if(to[i]!=fa[x][0]) { fa[to[i]][0]=x; dfs(to[i]); } } } int LCA(int x,int y) { if(x==y) return x; if(deep[x]<deep[y]) swap(x,y); int k=20; while(k>=0) { if(deep[fa[x][k]]>=deep[y]) x=fa[x][k]; k--; } if(x==y) return x; k=20; while(k>=0) { if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k]; k--; } return fa[x][0]; } void add(int x,int y) { to[++ce]=y; next[ce]=head[x]; head[x]=ce; } int main() { int n,m,q,i,j,k,x,y,v,fx,fy,last; scanf("%*d"); scanf("%d%d%d",&n,&m,&q); Set::init(n); for(i=1;i<=n;i++) scanf("%d",val+i),dis[i]=val[i]; sort(dis+1,dis+n+1); len=unique(dis+1,dis+n+1)-dis-1; for(i=1;i<=n;i++) val[i]=lower_bound(dis+1,dis+len+1,val[i])-dis; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y),add(y,x); Set::Link(x,y); } for(i=1;i<=n;i++) { if(!deep[i]) dfs(i); } for(i=1,last=0;i<=q;i++) { scanf("%s%d%d",op,&x,&y); x^=last,y^=last; if(op[0]=='Q') { scanf("%d",&k); k^=last; v=LCA(x,y); last=dis[query(1,len,root[x],root[y],root[v],root[fa[v][0]],k)]; printf("%d\n",last); } else { fx=Set::find(x),fy=Set::find(y); if(Set::size[fx]>Set::size[fy]) swap(x,y),swap(fx,fy); Set::Link(x,y); fa[x][0]=y; dfs(x); add(x,y),add(y,x); } } return 0; }
时间: 2024-11-08 21:45:30