EC Round 33 F. Subtree Minimum Query 主席树/线段树合并

  这题非常好!!!

  很简单的题目,给一个按照指定节点的树,树上有点权,你需要回答给定节点的子树中,和其距离不超过k的节点中,权值最小的。

  肯定首先一想,按照dfs序列建树,然后按照深度为下标,建立主席树,那么我们通过主席树相间得到区间状态,但是很不幸,区间最值不能通过减去历史版本的主席树得到。

  考虑照深度建立主席树,按照dfs下标建立,貌似可以耶!!!

  我们直接查询当前节点往下k深度的主席树,它保存的就是从深度为1-到深度为deep[p]+k深度的所有节点的dfs序对应的点权值

  我们查询子树对应区间的dfs序的最小值,就是答案啦!!!

   

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+6;
struct node{
   int l,r;
   int w;
}tree[maxn*40];
struct ID{
   int pre,bac;
}id[maxn];
int cnt,tot,dfsorder,mxdep;
int root[maxn*2];
int a[maxn],deepth[maxn];
int ver[maxn*2],Next[maxn*2],head[maxn];
int mp[maxn*2];
queue<int>q;
int n,r;
void add(int x,int y){
   ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
   ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void dfs(int u,int fa){
   deepth[u]=deepth[fa]+1;
   id[u].pre=++dfsorder;
   mxdep=max(mxdep,deepth[u]);
   for(int i=head[u];i;i=Next[i]){
       int v=ver[i];
       if(v==fa)continue;
       dfs(v,u);
   }
   id[u].bac=dfsorder;
}
void buildtree(int &rt,int l,int r){
   rt=++cnt;
   tree[rt].w=INF;
   if(l==r){
    return ;
   }
   int mid=(l+r)>>1;
   buildtree(tree[rt].l,l,mid);
   buildtree(tree[rt].r,mid+1,r);
}
void inserts(int l,int r,int pre,int &now,int pos,int w){
    now=++cnt;
    tree[now]=tree[pre];
    tree[now].w=min(tree[now].w,w);
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid){
        inserts(l,mid,tree[pre].l,tree[now].l,pos,w);
    }else {
        inserts(mid+1,r,tree[pre].r,tree[now].r,pos,w);
    }
}
int query(int rt,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr){
        return tree[rt].w;
    }
    int mid=(l+r)>>1;
    if (qr<=mid){
        return query(tree[rt].l,l,mid,ql,qr);
    }else if(ql>mid){
        return query(tree[rt].r,mid+1,r,ql,qr);
    }else {
        return min(query(tree[rt].l,l,mid,ql,mid),query(tree[rt].r,mid+1,r,mid+1,qr));
    }
}
void bfs(int s){
   q.push(s);
   int tmp=0;
   while(q.size()){
      int now=q.front();
      q.pop();
      inserts(1,2*n,root[tmp],root[tmp+1],id[now].pre,a[now]);
      mp[deepth[now]]=++tmp;
      for (int i=head[now];i;i=Next[i]){
          int nex=ver[i];
          if(deepth[nex]==deepth[now]+1){
            q.push(nex);
          }
      }
   }
}
int main(){
   int uu,vv;
   while(~scanf("%d%d",&n,&r)){
     tot=0;
     cnt=0;
     dfsorder=0;
     mxdep=0;
     for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
     }
     buildtree(root[0],1,n*2);
     for (int i=1;i<=n-1;i++){
        scanf("%d%d",&uu,&vv);
        add(uu,vv);
     }
     dfs(r,0);
     bfs(r);
     int op;
     int p,q;
     int ans=0;
     scanf("%d",&op);
     while(op--){
        scanf("%d%d",&p,&q);
        p=(p+ans)%n+1,q=(q+ans)%n;
        ans=query(root[mp[min(deepth[p]+q,mxdep)]],1,n*2,id[p].pre,id[p].bac);
        printf("%d\n",ans);
     }
   }
   return 0;
}

猜你喜欢

转载自www.cnblogs.com/bluefly-hrbust/p/11424639.html