CF893F Subtree Minimum Query 解题报告

CF893F Subtree Minimum Query

输入输出格式

输入格式:

The first line contains two integers \(n\) and \(r\) ( \(1<=r<=n<=100000\) ) — the number of vertices in the tree and the index of the root, respectively.

The second line contains n integers \(a_{1},a_{2},...,a_{n}\) ( \(1<=a_{i}<=10^{9}\) ) — the numbers written on the vertices.

Then \(n-1\) lines follow, each containing two integers \(x\) and \(y\) ( \(1<=x,y<=n\) ) and representing an edge between vertices \(x\) and \(y\) . It is guaranteed that these edges form a tree.

Next line contains one integer \(m\) ( \(1<=m<=10^{6}\) ) — the number of queries to process.

Then m lines follow, \(i\) -th line containing two numbers \(p_{i}\) and \(q_{i}\) , which can be used to restore \(i\) -th query ( \(1<=p_{i},q_{i}<=n\) ).

\(i\) -th query can be restored as follows:

Let last last be the answer for previous query (or \(0\) if \(i=1\) ). Then \(x_{i}=((p_{i}+last) \bmod n)+1\), and \(k_{i}=(q_{i}+last) \bmod n\) .

输出格式:

Print \(m\) integers. \(i\) -th of them has to be equal to the answer to \(i\) -th query.


题意大概就是给你一个有跟有点权的树,边权均为\(1\),每次询问一个点子树中距离Ta不超过\(k\)距离的点的最小点权。

发现\(dfs\)序限定子树是一个区间,可以放在线段树上,然后深度确定另一个区间,套一颗平衡树,就可以了。

事实上这道题还有一个高妙的做法,我并不会。

说不定以后会看一看呐


Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#define ls ch[now][0]
#define rs ch[now][1]
const int N=1e5+10;
int ch[N*30][2],dep[N*30],dat[N*30],mx[N*30],val[N*30],root[N<<2],tot;
int min(int x,int y){return x<y?x:y;}
void updata(int now){mx[now]=min(dat[now],min(mx[ls],mx[rs]));}
void split(int now,int k,int &x,int &y)
{
    if(!now){x=y=0;return;}
    if(dep[now]<=k)
        x=now,split(rs,k,rs,y);
    else
        y=now,split(ls,k,x,ls);
    updata(now);
}
int Merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(val[x]<val[y])
    {
        ch[x][1]=Merge(ch[x][1],y);
        updata(x);
        return x;
    }
    else
    {
        ch[y][0]=Merge(x,ch[y][0]);
        updata(y);
        return y;
    }
}
int New(int d,int de)
{
    val[++tot]=rand(),dat[tot]=mx[tot]=d,dep[tot]=de;
    return tot;
}
void Insert(int id,int d,int de)
{
    int x,y;
    split(root[id],de,x,y);
    root[id]=Merge(x,Merge(New(d,de),y));
}
int ask(int id,int de)
{
    int x,y,z;
    split(root[id],de,x,y);
    z=mx[x];
    root[id]=Merge(x,y);
    return z;
}
int query(int id,int L,int R,int l,int r,int de)
{
    if(l==L&&r==R)
        return ask(id,de);
    int Mid=L+R>>1;
    if(r<=Mid) return query(id<<1,L,Mid,l,r,de);
    else if(l>Mid) return query(id<<1|1,Mid+1,R,l,r,de);
    else return min(query(id<<1,L,Mid,l,Mid,de),query(id<<1|1,Mid+1,R,Mid+1,r,de));
}
int Next[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int dfn[N],low[N],Dep[N],ha[N],dfs_clock,n,m,rt,a[N];
void dfs(int now,int fa)
{
    dfn[now]=++dfs_clock;
    ha[dfs_clock]=now;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(v!=fa)
            Dep[v]=Dep[now]+1,dfs(v,now);
    }
    low[now]=dfs_clock;
}
void build(int id,int l,int r)
{
    for(int i=l;i<=r;i++)
        Insert(id,a[ha[i]],Dep[ha[i]]);
    if(l==r) return;
    int mid=l+r>>1;
    build(id<<1,l,mid),build(id<<1|1,mid+1,r);
}
int main()
{
    memset(dat,0x3f,sizeof(dat));
    memset(mx,0x3f,sizeof(mx));
    scanf("%d%d",&n,&rt);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs(rt,0);
    build(1,1,n);
    scanf("%d",&m);
    int las=0;
    for(int p,q,i=1;i<=m;i++)
    {
        scanf("%d%d",&p,&q);
        p=(p+las)%n+1,q=(q+las)%n;
        printf("%d\n",las=query(1,1,n,dfn[p],low[p],Dep[p]+q));
    }
    return 0;
}


2018.10.13

posted @ 2018-10-13 08:00  露迭月  阅读(237)  评论(0编辑  收藏  举报