CF893F Subtree Minimum Query(主席树)
我们发现要求的答案是depth[u]-min(depth[u]+k,mx)之间的属于他子树的最小值,mx是最深的深度
在线算法,不难想到用主席树对深度建树,这样就可以求取区间深度的信息,区间min没有可减性,但是并不影响本题做法
因为我们只需要查找指定dfs序区间中的答案即可,这样才是他子树中的答案,在前缀的深度当中,只有子树的答案才会被用来更新
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int rt[N]; int a[N]; int depth[N]; int st[N],ed[N],times; int h[N],ne[N],e[N],idx; vector<int> num[N]; int mx; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } struct node{ int l,r; int mi; }tr[N*30]; void dfs(int u,int fa){ int i; st[u]=++times; num[depth[u]].push_back(u); mx=max(mx,depth[u]); for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; depth[j]=depth[u]+1; dfs(j,u); } ed[u]=times; } void build(int &p,int l,int r){ p=++idx; tr[p].mi=1e9; if(l==r) return ; int mid=l+r>>1; build(tr[p].l,l,mid); build(tr[p].r,mid+1,r); } void insert(int &p,int q,int l,int r,int pos,int x){ p=++idx; tr[p]=tr[q]; tr[p].mi=min(tr[p].mi,x); if(l==r) return ; int mid=l+r>>1; if(pos<=mid) insert(tr[p].l,tr[q].l,l,mid,pos,x); else insert(tr[p].r,tr[q].r,mid+1,r,pos,x); } int query(int p,int l,int r,int L,int R){ if(L<=l&&R>=r){ return tr[p].mi; } int mid=l+r>>1; int ans=1e9; if(L<=mid) ans=min(ans,query(tr[p].l,l,mid,L,R)); if(R>mid) ans=min(ans,query(tr[p].r,mid+1,r,L,R)); return ans; } int main(){ ios::sync_with_stdio(false); int i; int n,p; cin>>n>>p; memset(h,-1,sizeof h); for(i=1;i<=n;i++){ cin>>a[i]; } for(i=1;i<n;i++){ int x,y; cin>>x>>y; add(x,y); add(y,x); } depth[p]=1; dfs(p,-1); build(rt[0],1,n); for(i=1;i<=mx;i++){ rt[i]=rt[i-1]; for(auto x:num[i]) insert(rt[i],rt[i],1,n,st[x],a[x]); } int last=0; int m; cin>>m; while(m--){ int p,q; cin>>p>>q; int x=(p+last)%n+1; int k=(q+last)%n; last=query(rt[min(depth[x]+k,mx)],1,n,st[x],ed[x]); cout<<last<<endl; } return 0; }
没有人不辛苦,只有人不喊疼