bzoj3123 [Sdoi2013]森林 可持久化线段树+启发式合并

Description


小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值。初始的时候,森林中有M条边。

小Z希望执行T个操作,操作有两类:

Q x y k查询点x到点y路径上所有的权值中,第k小的权值是多少。此操作保证点x和点y连通,同时这两个节点的路径上至少有k个点。
L x y在点x和点y之间连接一条边。保证完成此操作后,仍然是一片森林。

为了体现程序的在线性,我们把输入数据进行了加密。设lastans为程序上一次输出的结果,初始的时候lastans为0。

对于一个输入的操作Q x y k,其真实操作为Q x^lastans y^lastans k^lastans。
对于一个输入的操作L x y,其真实操作为L x^lastans y^lastans。其中^运算符表示异或,等价于pascal中的xor运算符。

请写一个程序來帮助小Z完成这些操作。

对于所有的数据,n,m,T<= 8∗10^4

Solution


最开始想到的是开两棵LCT分别搞形态和权值,然后我显然不会写
接着考虑树上开主席树,启发式合并,然后就过了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))

const int LIM=1000000000;
const int N=200005;
const int E=400005;

struct edge {int x,y,next;} e[E];
struct treeNode {int l,r,sum;} t[N*81];

int dep[N],fa[N][19],size[N];
int root[N],a[N],tot;
int ls[N],acs[N],edCnt;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}

void modify(int pre,int &now,int tl,int tr,int x,int v) {
    t[now=++tot]=t[pre]; t[now].sum++;
    if (tl==tr) return ;
    int mid=(tl+tr)>>1;
    if (x<=mid) modify(t[pre].l,t[now].l,tl,mid,x,v);
    else modify(t[pre].r,t[now].r,mid+1,tr,x,v);
}

int query(int lca,int flca,int x,int y,int tl,int tr,int k) {
    if (tl==tr) return tl;
    int tmp=t[t[x].l].sum+t[t[y].l].sum-t[t[lca].l].sum-t[t[flca].l].sum;
    int mid=(tl+tr)>>1;
    if (tmp>=k) return query(t[lca].l,t[flca].l,t[x].l,t[y].l,tl,mid,k);
    else return query(t[lca].r,t[flca].r,t[x].r,t[y].r,mid+1,tr,k-tmp);
}

void dfs(int now) {
    size[now]=1; acs[now]=fa[now][0];
    rep(i,1,18) fa[now][i]=fa[fa[now][i-1]][i-1];
    modify(root[fa[now][0]],root[now],1,LIM,a[now],1);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now][0]) continue;
        fa[e[i].y][0]=now;
        dep[e[i].y]=dep[now]+1;
        dfs(e[i].y);
        size[now]+=size[e[i].y];
    }
}

int get_lca(int x,int y) {
    if (dep[x]<dep[y]) std:: swap(x,y);
    drp(i,18,0) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if (x==y) return x;
    drp(i,18,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int get_father(int x) {
    if (!acs[x]) return x;
    return acs[x]=get_father(acs[x]);
}

int main(void) {
    int WJP=read();
    int n=read(),m=read(),T=read();
    rep(i,1,n) a[i]=read();
    rep(i,1,m) add_edge(read(),read());
    rep(i,1,n) if (!dep[i]) {
        dep[i]=1;
        dfs(i);
    }
    for (int lastans=0;T--;) {
        char opt[2]; scanf("%s",opt);
        int x=read()^lastans,y=read()^lastans;
        if (opt[0]=='Q') {
            int k=read()^lastans;
            int lca=get_lca(x,y);
            int flca=fa[lca][0];
            lastans=query(root[lca],root[flca],root[x],root[y],1,LIM,k);
            printf("%d\n", lastans);
        } else {
            if (size[get_father(x)]<size[get_father(y)]) std:: swap(x,y);
            fa[y][0]=x; dep[y]=dep[x]+1; add_edge(x,y);
            size[get_father(x)]+=size[get_father(y)];
            dfs(y);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80698654