codeforce893 F. Subtree Minimum Query 線段樹合併
阿新 • • 發佈:2018-12-17
給定一棵樹,每個節點都有自己的權值,對於每個詢問,查詢x的子樹中與x深度差不超過y的節點的最小權值
對樹上的每一個節點以深度建立動態線段樹,父節點合併子節點的線段樹,O(logn)查詢
#include<bits/stdc++.h> using namespace std; const int MAX=1e5+5; const int INF=0x3f3f3f3f; int n,m,r,a[MAX],ls[MAX<<6],rs[MAX<<6],val[MAX<<6],d[MAX],rt[MAX],cnt; struct P { int to,nxt; }e[MAX<<1]; int head[MAX],tot; void init() { memset(head,-1,sizeof(head)); memset(val,0,sizeof(val)); memset(rt,0,sizeof(rt)); memset(ls,0,sizeof(ls)); memset(rs,0,sizeof(rs)); tot=0;cnt=0;val[0]=INF; } void adde(int u,int v) { e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot++; } void update(int &x,int l,int r,int p,int v) { x=++cnt;if(l==r){val[x]=v;return;} int mid=(l+r)>>1; if(p<=mid) update(ls[x],l,mid,p,v); else update(rs[x],mid+1,r,p,v); val[x]=min(val[ls[x]],val[rs[x]]); } int merge_(int u,int v) { if(!u) return v; if(!v) return u; int x=++cnt; ls[x]=merge_(ls[u],ls[v]); rs[x]=merge_(rs[u],rs[v]); if(ls[x]||rs[x]) val[x]=min(val[ls[x]],val[rs[x]]); else val[x]=min(val[u],val[v]); return x; } int query(int x,int l,int r,int L,int R) { if(!x) return INF; if(l==L&&r==R) return val[x]; int mid=(l+r)>>1; if(R<=mid) return query(ls[x],l,mid,L,R); if(L>mid) return query(rs[x],mid+1,r,L,R); return min(query(ls[x],l,mid,L,mid),query(rs[x],mid+1,r,mid+1,R)); } void dfs(int u,int fa) { update(rt[u],1,100000,d[u],a[u]); for(int i=head[u];~i;i=e[i].nxt) { int v=e[i].to; if(v==fa) continue; d[v]=d[u]+1; dfs(v,u); rt[u]=merge_(rt[u],rt[v]); } } int main() { int x,y; while(~scanf("%d%d",&n,&r)) { init(); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i<n;++i) { scanf("%d%d",&x,&y); adde(x,y);adde(y,x); } d[r]=1;dfs(r,0); scanf("%d",&m); int last=0; while(m--) { scanf("%d%d",&x,&y); x=(x+last)%n+1;y=(y+last)%n; printf("%d\n",last=query(rt[x],1,100000,d[x],min(100000,d[x]+y))); } } return 0; }