BZOJ 3123 SDOI2013 森林 可持久化线段树+倍增LCA+启发式合并

来源:互联网 发布:js函数式编程 编辑:程序博客网 时间:2024/06/06 07:50

题目大意:给定一棵森林,每个点有权值,提供两种操作:

1.查询两点间路径上第k小的权值

2.将两个点之间连一条边 保证连接后仍是一座森林

可持久化线段树部分同Count On A Tree 只是这道题加了个连接操作

对于连接操作我们要用到启发式合并 就是把小的那棵树暴力重建 很简单的一个操作但是可以证明是均摊O(nlogn)的

大小我用了并查集 其实记录根就可以了

此外本题的多组数据是在逗比 记住testcase恒等于1就是了

NND我倍增LCA又写错了0.0 预处理时居然从大往小写的0.0 样例还过了0.0

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 80100using namespace std;struct Tree{Tree *ls,*rs;int num;}*tree[M],mempool[20002000],*C=mempool;struct abcd{int to,next;}table[M<<1];int head[M],tot;int n,m,q,ans;int a[M],fa[M][20],dpt[M],root[M],siz[M],stack[M],top;int Find(int x){if(!root[x])siz[x]=1,root[x]=x;if(root[x]==x)return x;return root[x]=Find(root[x]);}inline void Unite(int x,int y){int fx=Find(x);int fy=Find(y);root[fy]=fx;siz[fx]+=siz[fy];}inline void Add(int x,int y){table[++tot].to=y;table[tot].next=head[x];head[x]=tot;}inline Tree* New_Node(Tree* _,Tree* __,int ___){C->ls=_;C->rs=__;C->num=___;return C++;}Tree* Build_Tree(Tree *p,int x,int y,int num){int mid=x+y>>1;if(x==y)return New_Node(0x0,0x0,p->num+1);if(num<=mid)return New_Node(Build_Tree(p->ls,x,mid,num),p->rs,p->num+1);elsereturn New_Node(p->ls,Build_Tree(p->rs,mid+1,y,num),p->num+1);}int Get_Kth(Tree *p1,Tree *p2,Tree *p3,Tree *p4,int x,int y,int k){int mid=x+y>>1;if(x==y)return mid;int temp = p1->ls->num + p2->ls->num - p3->ls->num - p4->ls->num;if(k<=temp)return Get_Kth(p1->ls,p2->ls,p3->ls,p4->ls,x,mid,k);elsereturn Get_Kth(p1->rs,p2->rs,p3->rs,p4->rs,mid+1,y,k-temp);}void DFS1(int x){int i;dpt[x]=dpt[fa[x][0]]+1;tree[x]=Build_Tree(tree[fa[x][0]],0,1000000000,a[x]);for(i=head[x];i;i=table[i].next){if(table[i].to==fa[x][0])continue;fa[table[i].to][0]=x;DFS1(table[i].to);}}void DFS2(int x,int from){int i;fa[x][0]=from;dpt[x]=dpt[fa[x][0]]+1;tree[x]=Build_Tree(tree[fa[x][0]],0,1000000000,a[x]);stack[++top]=x;for(i=head[x];i;i=table[i].next){if(table[i].to==from)continue;DFS2(table[i].to,x);}}inline int LCA(int x,int y){int j;if(dpt[x]<dpt[y])swap(x,y);for(j=19;~j;j--)if(dpt[fa[x][j]]>=dpt[y])x=fa[x][j];if(x==y)return x;for(j=19;~j;j--)if(fa[x][j]!=fa[y][j])x=fa[x][j],y=fa[y][j];return fa[x][0];}int main(){int T,i,j,x,y,k;char p[10];cin>>T;cin>>n>>m>>q;for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=1;i<=m;i++)scanf("%d%d",&x,&y),Add(x,y),Add(y,x),Unite(x,y);tree[0]=New_Node(C,C,0);for(i=1;i<=n;i++)if(!fa[i][0])DFS1(i);for(j=1;j<=19;j++)for(i=1;i<=n;i++)fa[i][j]=fa[ fa[i][j-1] ][j-1];for(i=1;i<=q;i++){scanf("%s%d%d",p,&x,&y);x^=ans;y^=ans;if(p[0]=='Q'){scanf("%d",&k);k^=ans;int lca=LCA(x,y);printf("%d\n", ans=Get_Kth(tree[x],tree[y],tree[lca],tree[fa[lca][0]],0,1000000000,k) );}else{if(siz[Find(x)]>siz[Find(y)])swap(x,y);top=0;DFS2(x,y);Unite(x,y);Add(x,y),Add(y,x);for(j=1;j<=19;j++)for(k=1;k<=top;k++)fa[ stack[k] ][j]=fa[ fa[ stack[k] ][j-1] ][j-1];}}}


0 0
原创粉丝点击