抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

题面:

传送门:Codeforces 题目大意:给你一颗有根树,点有权值,问你每个节点的子树中距离其不超过k的点的权值的最小值。(边权均为1,强制在线)


Solution

这题很有意思。 我们一般看到这种距离不超过k的题目,第一反应一般是建以深度为下标,以dfs序为时间轴的的主席树。 很不幸,区间最小值并不能通过减去历史状态得出某个子树的状态。 所以说,这题妙在思想的转换。 考虑以dfs序为下标,以深度为时间轴建一颗主席树。 我们可以bfs,按深度一层层地把点加进去。 这样子,我们就可以查询对应深度之内的这颗子树的最小权值啦。 就酱,我们就可以把这题切掉啦ヽ( ̄▽ ̄)ノ


Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=100000+1000;
const int M=30*N;
int n,r,a[N];
vector <int> e[N];
struct SegmentTree
{
static const int inf=0x3f3f3f3f;
#define mid ((now_l+now_r)>>1)
int MIN[M],son[M][2],cnt;
inline void update(int now)
{
MIN[now]=min(MIN[son[now][0]],MIN[son[now][1]]);
}
void Build(int now,int now_l,int now_r)
{
if(now_l==now_r)
{
MIN[now]=inf;
return;
}
Build(son[now][0]=++cnt,now_l,mid);
Build(son[now][1]=++cnt,mid+1,now_r);
update(now);
}
void Change(int x,int num,int now,int pre,int now_l,int now_r)
{
if(now_l==now_r)
{
MIN[now]=num;
return;
}
if(x<=mid) son[now][1]=son[pre][1],Change(x,num,son[now][0]=++cnt,son[pre][0],now_l,mid);
else son[now][0]=son[pre][0],Change(x,num,son[now][1]=++cnt,son[pre][1],mid+1,now_r);
update(now);
}
int Query(int L,int R,int now,int now_l,int now_r)
{
if(now_l>=L and now_r<=R)
return MIN[now];
int ans=inf;
if(L<=mid) ans=min(ans,Query(L,R,son[now][0],now_l,mid));
if(R>mid) ans=min(ans,Query(L,R,son[now][1],mid+1,now_r));
return ans;
}
void Print(int now,int now_l,int now_r)
{
cerr<<"no."<<now<<" now_l&r:"<<now_l<<" "<<now_r<<" sonl&r"<<son[now][0]<<" "<<son[now][1]<<" MIN:"<<MIN[now]<<endl;
if(now_l!=now_r)
{
Print(son[now][0],now_l,mid);
Print(son[now][1],mid+1,now_r);
}
}
#undef mid
}sgt;
int dfn[N],depth[N],dfn_to,size[N],depth_MAX;
void dfs(int now)
{
depth_MAX=max(depth_MAX,depth[now]);
dfn[now]=++dfn_to;
size[now]=1;
for(int i=0;i<int(e[now].size());i++)
if(dfn[e[now][i]]==0)
{
depth[e[now][i]]=depth[now]+1;
dfs(e[now][i]);
size[now]+=size[e[now][i]];
}
}
int dl[N],front,tail,root[N];
void bfs()
{
dl[tail++]=r;
int depth_now=0;
while(tail>front)
{
int now=dl[front];
int temp=root[depth_now];
if(depth[now]!=depth_now)
{
depth_now=depth[now];
temp=root[depth_now-1];
}
root[depth_now]=++sgt.cnt;
sgt.Change(dfn[now],a[now],root[depth_now],temp,1,n);
//sgt.Print(root[depth_now],1,n);
//cerr<<endl;
for(int i=0;i<int(e[now].size());i++)
if(depth[e[now][i]]>depth[now])
dl[tail++]=e[now][i];
front++;
}
}
int main()
{
n=read(),r=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<n;i++)
{
int s=read(),t=read();
e[s].push_back(t);
e[t].push_back(s);
}

depth[r]=1;
dfs(r);
sgt.Build(0,1,n);
//sgt.Print(0,1,n);
//cerr<<endl;
bfs();

int m=read(),lans=0;
for(int i=1;i<=m;i++)
{
int x=read(),K=read();
x=((x+lans)%n)+1,K=(K+lans)%n;
int temp=min(depth[x]+K,depth_MAX);
lans=sgt.Query(dfn[x],dfn[x]+size[x]-1,root[temp],1,n);
printf("%d\n",lans);
}
return 0;
}

评论