版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 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;
}