森林

来源:互联网 发布:半包合同知乎 编辑:程序博客网 时间:2024/04/27 20:10

森林

题目描述:贴个传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3123

题解

用主席树维护区间k小。对于每个节点,以父亲节点为上一版本。
对于每次加边,进行启发式合并,暴力搜索子树内每几个节点,重构主席树即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<algorithm>#define N 80005#define P 17using namespace std;int cyc,n,m,Q,cnt,pre,s[N],Tnum,num[N];int w[N][P+1],rt[N],flag[N],dep[N];int k,la[N],ff[N*2],fa[N],size[N];struct node{int a,b;}map[N*2];struct point{int lc,rc,size;}t[N*300];int get(int x){return x^pre;}void add(int a,int b){  map[++k]=(node){a,b};ff[k]=la[a];la[a]=k;  map[++k]=(node){b,a};ff[k]=la[b];la[b]=k;}class func_seg_tree{  public:  void modify(int &x,int pre,int l,int r,int des)  {    t[x=++cnt]=t[pre];t[x].size++;    if(l==r)return;    int mid=l+r>>1;    if(des<=mid)modify(t[x].lc,t[pre].lc,l,mid,des);    else modify(t[x].rc,t[pre].rc,mid+1,r,des);  }  int qry(int a,int b,int c,int d,int l,int r,int k)  {    if(l==r)return num[l];    int A=t[t[a].lc].size,B=t[t[b].lc].size;    int C=t[t[c].lc].size,D=t[t[d].lc].size;    int sum=A+B-C-D,mid=l+r>>1;    if(k<=sum)return qry(t[a].lc,t[b].lc,t[c].lc,t[d].lc,l,mid,k);    return qry(t[a].rc,t[b].rc,t[c].rc,t[d].rc,mid+1,r,k-sum);  }  }T;void dfs(int x){  flag[x]=1;size[x]=1;  T.modify(rt[x],rt[w[x][0]],1,Tnum,s[x]);  for(int i=1;i<=P;i++)    w[x][i]=w[w[x][i-1]][i-1];  for(int a=la[x];a;a=ff[a])    if(!flag[map[a].b])    {      w[map[a].b][0]=x;dep[map[a].b]=dep[x]+1;      dfs(map[a].b);size[x]+=size[map[a].b];    }  flag[x]=0;}int lca(int x,int y){  if(dep[x]<dep[y])swap(x,y);  for(int i=P;i>=0;i--)    if(dep[w[x][i]]>=dep[y])x=w[x][i];  if(x==y)return x;  for(int i=P;i>=0;i--)    if(w[x][i]!=w[y][i])x=w[x][i],y=w[y][i];  return w[x][0];}int find(int x){  if(!fa[x])return x;  return fa[x]=find(fa[x]);}int main(){  int a,b,x,y,z,pos,X,Y;char ch;  scanf("%d%d%d%d",&cyc,&n,&m,&Q);  for(int i=1;i<=n;i++)    scanf("%d",&s[i]),num[i]=s[i];  sort(num+1,num+n+1);  Tnum=unique(num+1,num+n+1)-num-1;  for(int i=1;i<=n;i++)    s[i]=lower_bound(num+1,num+Tnum+1,s[i])-num;  for(int i=1;i<=m;i++)    scanf("%d%d",&a,&b),add(a,b);  for(int i=1;i<=n;i++)if(!w[i][0])dep[i]=1,dfs(i);  while(Q--)  {    scanf(" %c%d%d",&ch,&x,&y);    x=get(x);y=get(y);    if(ch=='Q')    {      scanf("%d",&z);z=get(z);pos=lca(x,y);      printf("%d\n",pre=T.qry(rt[x],rt[y],rt[pos],rt[w[pos][0]],1,Tnum,z));    }    else    {      int X=find(x),Y=find(y);      if(size[X]>size[Y])swap(x,y);      w[x][0]=y;dep[x]=dep[y]+1;      dfs(x);add(x,y);    }  }  return 0;}
0 0
原创粉丝点击