1. 程式人生 > >[CF893F]Subtree Minimum Query (主席樹)

[CF893F]Subtree Minimum Query (主席樹)

題面:

傳送門:http://codeforces.com/problemset/problem/893/F

題目大意:給你一顆有根樹,點有權值,問你每個節點的子樹中距離其不超過k的點的權值的最小值。(邊權均為1,強制線上


Solution

這題很有意思。

 

我們一般看到這種距離不超過k的題目,第一反應一般是建以深度為下標,以dfs序為時間軸的的主席樹。

很不幸,區間最小值並不能通過減去歷史狀態得出某個子樹的狀態

 

所以說,這題妙在思想的轉換。

考慮以dfs序為下標,以深度為時間軸建一顆主席樹

我們可以bfs,按深度一層層地把點加進去。

這樣子,我們就可以查詢對應深度之內的這顆子樹的最小權值啦。

 

就醬,我們就可以把這題切掉啦ヽ( ̄▽ ̄)ノ


Code

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