jzoj5850 e 树上主席树

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82051862

Description


这里写图片描述

Solution


不难发现S为k个点到它们lca的路径的并。对于询问我们在树上建可持久化权值线段树,然后找前驱和后继即可。这样是一个log的,然后就做完了
一个比较好想+好写的做法是树链剖分+set,这个可以拿来拍
如果知道一堆点的lca等价于其中dfs序最小和最大两个点的lca,那么就可以跑得快

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st,_=ed;i<=_;++i)

const int INF=1000000000;
const int N=100005;
const int E=200005;

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

int pos[N],dep[N],fa[N],bl[N],size[N];
int root[N],v[N],tot,n,m;
int ls[N],vec[N],edCnt;

inline 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;
}

inline void write(int x) {
    if (x>9) write(x/10);
    putchar(x%10+'0');
}

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 dfs1(int now) {
    size[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now]) continue;
        fa[e[i].y]=now; dep[e[i].y]=dep[now]+1;
        dfs1(e[i].y); size[now]+=size[e[i].y];
    }
}

void modify(int pre,int &now,int tl,int tr,int x) {
    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);
    else modify(t[pre].r,t[now].r,mid+1,tr,x);
}

void dfs2(int now,int up) {
    pos[now]=++pos[0]; bl[now]=up; int mx=0;
    modify(root[fa[now]],root[now],1,INF,v[now]);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
    }
    if (!mx) return ; dfs2(mx,up);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
    }
}

int get_lca(int x,int y) {
    for (;bl[x]!=bl[y];) {
        if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
        x=fa[bl[x]];
    }
    if (dep[x]<dep[y]) return x;
    return y;
}

int lower(int pre,int now,int tl,int tr,int x) {
    if (!(t[now].sum-t[pre].sum)) return 0;
    if (tl==tr) return tl;
    int mid=(tl+tr)>>1;
    if (x<=mid) return lower(t[pre].l,t[now].l,tl,mid,x);
    int tmp=lower(t[pre].r,t[now].r,mid+1,tr,x);
    if (tmp) return tmp;
    return lower(t[pre].l,t[now].l,tl,mid,x);
}

int upper(int pre,int now,int tl,int tr,int x) {
    if (!(t[now].sum-t[pre].sum)) return 0;
    if (tl==tr) return tl;
    int mid=(tl+tr)>>1;
    if (x>mid) return upper(t[pre].r,t[now].r,mid+1,tr,x);
    int tmp=upper(t[pre].l,t[now].l,tl,mid,x);
    if (tmp) return tmp;
    return upper(t[pre].r,t[now].r,mid+1,tr,x);
}

bool cmp(int a,int b) {
    return pos[a]<pos[b];
}

int main(void) {
    freopen("e.in","r",stdin);
    freopen("e.out","w",stdout);
    int n=read(),T=read(),type=read();
    rep(i,1,n) v[i]=read();
    rep(i,2,n) add_edge(read(),read());
    dep[1]=1; dfs1(1); dfs2(1,1);
    for (int lastans=0;T--;) {
        int r=read(),k=read(); vec[0]=0;
        int r1=n+2,r2=n+3; pos[r1]=INF,pos[r2]=0;
        rep(i,1,k) {
            int x=read();
            x=(x-1+lastans*type)%n+1;
            vec[++vec[0]]=x;
            if (pos[x]<pos[r1]) r1=x;
            if (pos[x]>pos[r2]) r2=x;
        }
        int lca=get_lca(r1,r2),ans=INF;
        rep(i,1,vec[0]) {
            int now=vec[i],ff=fa[lca];
            int upp=upper(root[now],root[ff],1,INF,r);
            if (upp) ans=std:: min(ans,abs(upp-r));
            int low=lower(root[now],root[ff],1,INF,r);
            if (low) ans=std:: min(ans,abs(low-r));
        }
        write(ans); putchar('\n');
        lastans=ans;
    }
    return 0;
}

猜你喜欢

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