BZOJ 3123 森林

Posted on 2017-02-21 10:36  ziliuziliu  阅读(151)  评论(0编辑  收藏  举报

题解网上都有。。。

注意主席树的写法吧。。。我这样写可能空间小点吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxv 80050
#define maxe 200050
using namespace std;
int testcase,n,m,q,lastans=0,father[maxv],size[maxv],dis[maxv],anc[maxv][20],g[maxv],nume=1,val[maxv],hash[maxv];;
int root[maxv],ls[maxv*50],rs[maxv*50],sum[maxv*50],x,y,k;
char type[4];
int tot=0,cnt=0,lab,times=0,vis[maxv];
struct edge
{
    int v,nxt;
}e[maxe];
void addedge(int u,int v)
{
    e[++nume].v=v;e[nume].nxt=g[u];
    g[u]=nume;
}
int getfather(int x)
{
    if (father[x]!=x) father[x]=getfather(father[x]);
    return father[x];
}
void build(int pre,int &now,int left,int right,int pos)
{
    if (!now) now=++tot;sum[now]=sum[pre]+1;
    if (left==right) return;
    int mid=(left+right)>>1;
    if (pos<=mid) {build(ls[pre],ls[now],left,mid,pos);rs[now]=rs[pre];}
    else {build(rs[pre],rs[now],mid+1,right,pos);ls[now]=ls[pre];}
}
void dfs1(int x)
{
    father[x]=lab;vis[x]=1;size[lab]++;
    build(root[anc[x][0]],root[x],1,n,val[x]);
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v==anc[x][0]) continue;
        dis[v]=dis[x]+1;anc[v][0]=x;
        for (int e=1;e<=19;e++) anc[v][e]=anc[anc[v][e-1]][e-1];
        dfs1(v);
    }
}
void dfs2(int x)
{
    build(root[anc[x][0]],root[x],1,n,val[x]);
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v==anc[x][0]) continue;
        dis[v]=dis[x]+1;anc[v][0]=x;
        for (int e=1;e<=19;e++) anc[v][e]=anc[anc[v][e-1]][e-1];
        dfs2(v);
    }
}
int lca(int x,int y)
{
    if (dis[x]<dis[y]) swap(x,y);
    for (int e=19;e>=0;e--)
    {
        if (dis[anc[x][e]]>=dis[y] && anc[x][e])
            x=anc[x][e];
    }
    if (x==y) return x;
    for (int e=19;e>=0;e--)
    {
        if (anc[x][e]!=anc[y][e])
        {
            x=anc[x][e];
            y=anc[y][e];
        }
    }
    return anc[x][0];
}
int ask(int t1,int t2,int t3,int t4,int left,int right,int k)
{
    if (left==right) return left;
    int r=sum[ls[t1]]+sum[ls[t2]]-sum[ls[t3]]-sum[ls[t4]];
    int r1=sum[ls[t1]],r2=sum[ls[t2]],r3=sum[ls[t3]],r4=sum[ls[t4]];
    int mid=(left+right)>>1;
    if (k<=r) return ask(ls[t1],ls[t2],ls[t3],ls[t4],left,mid,k);
    else return ask(rs[t1],rs[t2],rs[t3],rs[t4],mid+1,right,k-r);
}
void link(int x,int y)
{
    int f1=getfather(x),f2=getfather(y);
    if (size[f1]>size[f2]) {swap(f1,f2);swap(x,y);}
    father[f1]=f2;size[f2]+=size[f1];
    dis[x]=dis[y]+1;anc[x][0]=y;for (int e=1;e<=19;e++) anc[x][e]=anc[anc[x][e-1]][e-1];
    dfs2(x);
}
int main()
{
    scanf("%d",&testcase);
    scanf("%d%d%d",&n,&m,&q);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);hash[++cnt]=val[i];
        father[i]=i;
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);addedge(y,x);
    }
    sort(hash+1,hash+cnt+1);cnt=unique(hash+1,hash+cnt+1)-hash-1;
    for (int i=1;i<=n;i++) val[i]=lower_bound(hash+1,hash+cnt+1,val[i])-hash;
    times++;
    for (int i=1;i<=n;i++)
    {
        if (vis[i]) continue;
        lab=i;dfs1(i);
    }
    for (int i=1;i<=q;i++)
    {
        scanf("%s",&type);
        if (type[0]=='Q')
        {
            scanf("%d%d%d",&x,&y,&k);
            x^=lastans;y^=lastans;k^=lastans;
            int t=lca(x,y);
            lastans=hash[ask(root[x],root[y],root[t],root[anc[t][0]],1,n,k)];
            printf("%d\n",lastans);    
        }
        else
        {
            scanf("%d%d",&x,&y);
            x^=lastans;y^=lastans;
            link(x,y);addedge(x,y);addedge(y,x);
        }
    }
    return 0;
}