Description
Input
Output
Data Constraint
分析:
最小连通块可以看作是所有点到他们的
lca
l
c
a
路径的并集,因为是取最小值,所以重复的不会有贡献。
我们对这棵树建可持久化线段树,每个点的线段树相当于他的父亲加上一条链。然后就相当于在这些线段树上找前驱与后继。
一开始我想到二分答案,再判断,这样做是
O(nlog2n)
O
(
n
l
o
g
2
n
)
的,然后我被卡掉了。然后还有一种直接线段树找前驱的方法,如果当前点小于
mid
m
i
d
,直接找左半部分,否则先找右半部分,如果没有再找左半部,这样做应该是和k-d tree找最近点对差不多的。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=1e5+7;
const int maxp=1e9;
using namespace std;
int n,test,m,typ,x,y,cnt,l,r,lastans;
int a[maxn],root[maxn],f[maxn][20],b[maxn*3],ls[maxn],dep[maxn];
struct node{
int l,r,data;
}t[maxn*50];
struct edge{
int y,next;
}g[maxn*2];
void add(int x,int y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
void ins(int &p,int q,int l,int r,int x,int k)
{
if (!p) p=++cnt;
t[p].data=t[q].data+k;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) t[p].r=t[q].r,ins(t[p].l,t[q].l,l,mid,x,k);
else t[p].l=t[q].l,ins(t[p].r,t[q].r,mid+1,r,x,k);
}
int getpre(int p,int q,int l,int r,int x)
{
if (!(t[p].data-t[q].data)) return 0;
if (l==r) return l;
int mid=(l+r)/2;
if (x<=mid) return getpre(t[p].l,t[q].l,l,mid,x);
else
{
int tmp=getpre(t[p].r,t[q].r,mid+1,r,x);
if (tmp) return tmp;
return getpre(t[p].l,t[q].l,l,mid,x);
}
}
int getnext(int p,int q,int l,int r,int x)
{
if (!(t[p].data-t[q].data)) return 0;
if (l==r) return l;
int mid=(l+r)/2;
if (x>mid) return getnext(t[p].r,t[q].r,mid+1,r,x);
else
{
int tmp=getnext(t[p].l,t[q].l,l,mid,x);
if (tmp) return tmp;
return getnext(t[p].r,t[q].r,mid+1,r,x);
}
}
void dfs(int x,int fa)
{
f[x][0]=fa;
dep[x]=dep[fa]+1;
ins(root[x],root[fa],1,maxp,a[x],1);
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (y==fa) continue;
dfs(y,x);
}
}
int lca(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
int d=dep[y]-dep[x],k=19,t=1<<k;
while (d)
{
if (d>=t) d-=t,y=f[y][k];
t/=2,k--;
}
if (x==y) return x;
k=19;
while (k>=0)
{
if (f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
k--;
}
return f[x][0];
}
int main()
{
freopen("e.in","r",stdin);
freopen("e.out","w",stdout);
scanf("%d%d%d",&n,&test,&typ);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
cnt=0;
dfs(1,0);
for (int j=1;j<20;j++)
{
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
}
}
for (int i=1;i<=test;i++)
{
scanf("%d%d",&x,&m);
for (int j=1;j<=m;j++)
{
scanf("%d",&b[j]);
b[j]=(b[j]-1+lastans*typ)%n+1;
}
int d=b[1];
for (int j=2;j<=m;j++) d=lca(d,b[j]);
d=f[d][0];
lastans=2e9;
for (int j=1;j<=m;j++)
{
int tmp1=getpre(root[b[j]],root[d],1,maxp,x);
int tmp2=getnext(root[b[j]],root[d],1,maxp,x);
if (tmp1) lastans=min(lastans,x-tmp1);
if (tmp2) lastans=min(lastans,tmp2-x);
}
printf("%d\n",lastans);
}
}