题目链接:https://cn.vjudge.net/problem/CodeForces-893F
题目大意:给你n个点,每一个点有权值,然后这n个点会构成一棵树,边权为1.然后有q次询问,每一次询问包括t1和t2。让你找出以t1为根节点的树上,距离t1不超过t2的节点,最小的点权值。
每一次的t1是(上次询问的结果+t1)%n+1,t2是(上次询问的结果+t1)。所以就必须的强制在线了。
具体思路:线段树合并,通过dfs序进行遍历,以每一个点的深度作为下标建树。一开始,每一个节点储存的是从当前节点到叶子节点的最小的值。但是题目中要求的是以当前节点为根节点的长度<=k的最小值,这个时候我们需要往上更新。这个更新过程就需要用到线段树合并了,把每一个子节点归并到他的父亲节点上,这样逐渐的往上递归就可以了,因为父亲节点要获取子节点的所有的信息。
然后顺便学习了一下线段树的动态开点,这个过程有点像主席树的创建过程,并不是一开始就吧线段树建立好,而是用到哪个点就给这个点编号。
这个题搞了一天才明白,,,感谢周恩杰的帮助([]~( ̄▽ ̄)~*)。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<cmath> 4 #include<stdio.h> 5 #include<algorithm> 6 #include<cstring> 7 #include<queue> 8 using namespace std; 9 # define ll long long 10 # define lson l,m,rt<<1 11 # define rson m+1,r,rt<<1|1 12 const int maxn = 2e5+100; 13 # define inf 0x3f3f3f3f 14 # define ll_inf 0x3f3f3f3f3f3f3f 15 struct Edge{ 16 ll to,nex; 17 }edge[maxn<<2]; 18 struct node{ 19 ll val; 20 ll ch[3]; 21 void in(){val=ll_inf,ch[0]=ch[1]=0;} 22 }q[maxn*40]; 23 ll head[maxn],num,depth[maxn],tot,n; 24 ll root[maxn]; 25 ll a[maxn]; 26 void init(ll n){ 27 for(ll i=0;i<=n;i++){ 28 head[i]=-1; 29 } 30 num=0; 31 tot=0; 32 } 33 void addedge(ll fr,ll to){ 34 edge[num].nex=head[fr]; 35 edge[num].to=to; 36 head[fr]=num++; 37 } 38 #define lch q[rt].ch[0] 39 #define rch q[rt].ch[1] 40 void up(ll rt){ 41 q[rt].val=min(q[lch].val,q[rch].val); 42 } 43 void update(ll pos,ll val,ll l,ll r,ll &rt){ 44 q[rt=++tot].in(); 45 if(l==r){ 46 q[rt].val=val; 47 return ; 48 } 49 ll mid=(l+r)>>1; 50 if(pos<=mid)update(pos,val,l,mid,lch); 51 else update(pos,val,mid+1,r,rch); 52 up(rt); 53 } 54 ll merge(ll u,ll v){ 55 if(!v)return u; 56 if(!u)return v; 57 ll tmp=++tot; 58 q[tmp].in(); 59 q[tmp].ch[0]=merge(q[u].ch[0],q[v].ch[0]); 60 q[tmp].ch[1]=merge(q[u].ch[1],q[v].ch[1]); 61 q[tmp].val=min(q[u].val,q[v].val); 62 return tmp;//注意这个地方返回的是tmp,而不是tot。因为这个过程tot还会增加,而这个地方需要的是原来的tot,所以返回的是tmp 63 } 64 void dfs(ll u,ll fr,ll dep){ 65 depth[u]=dep; 66 update(depth[u],a[u],1,n,root[u]); 67 for(ll i=head[u];i!=-1;i=edge[i].nex){ 68 ll to=edge[i].to; 69 if(to==fr)continue; 70 dfs(to,u,dep+1); 71 root[u]=merge(root[u],root[to]); 72 } 73 } 74 ll query(ll L,ll R,ll l,ll r,ll x){ 75 if(r<L||l>R)return ll_inf; 76 if(L<=l&&R>=r)return q[x].val; 77 ll mid=(l+r)>>1; 78 return min(query(L,R,l,mid,q[x].ch[0]),query(L,R,mid+1,r,q[x].ch[1])); 79 } 80 int main(){ 81 ll m,st,ed; 82 scanf("%lld %lld",&n,&m); 83 for(ll i=1;i<=n;i++){ 84 scanf("%lld",&a[i]); 85 } 86 init(n); 87 for(ll i=2;i<=n;i++){ 88 scanf("%lld %lld",&st,&ed); 89 addedge(st,ed); 90 addedge(ed,st); 91 } 92 q[0].in(); 93 dfs(m,m,1); 94 //for(int i=1;i<=n;i++){ 95 //cout<<i<<" "<<root[i]<<endl; 96 //} 97 ll Case=0,last=0; 98 scanf("%lld",&Case); 99 while(Case--){ 100 scanf("%lld %lld",&st,&ed); 101 st=(last+st)%n+1; 102 ed=(last+ed)%n; 103 //cout<<depth[st]<<" "<<depth[st]+ed<<endl; 104 last=query(depth[st],depth[st]+ed,1,n,root[st]); 105 printf("%lld ",last); 106 } 107 return 0; 108 }