• 树上路径(path)


    树上路径(path)

    题目描述

     

     

    Berland,有n个城堡。

    每个城堡恰好属于一个领主。不同的城堡属于不同的领主。在所有领主中有一个是国王,其他的每个领主都直接隶属于另一位领主,并且间接隶属于国王。一位领主可以拥有任意数量的下属。这些城堡被一些双向的道路连接。两个城堡是连接的当且仅当他们的主人中一位直接隶属于另一位。

    每一年,在Berland会发生以下两件事中的一件:

    1.野蛮人攻击了城堡c。这是城堡c第一次也会是最后一次被攻击,因为野蛮人从来不攻击同一座城堡超过一次。

    2.一个骑士从城堡a出发前往到城堡b。骑士从不重复经过同一座城堡,因此他的路线是唯一确定的。

    现在考虑第二类事件。由于从城堡ab的路途遥远,每个骑士会在他经过的某个城堡停下来休息一次。根据规则,骑士不能停留在第 y 年以后受到过攻击的城堡中。所以,骑士选择了途径的第k个从第 y+1 年开始到现在(当时)没有被攻击过的城堡(不算城堡ab)。

    你,伟大的历史学家,知道Berland历史上的所有m个事件。请你计算,每个骑士是在哪个城堡休息的。如果在从城堡a到城堡b的路上少于k座城堡,那么你可以断定有关这个骑士的记载是有误的。

     

     

    输入

     

     

     

    第一行包含一个整数N,表示城堡数目。

    第二行包含N个整数,依次表示编号为 1...N 的城堡领主的上级。特别的,国王没有上级,故用 0 表示。

    第三行包含一个整数M,表示事件数目。

    接下来M行,每行描述一个事件:

    若是第1类事件,则包含两个整数,依次是1ci

    若是第2类事件,则包含五个整数,依次是2aibikiyi

     

     

     

     

    输出

     

     

    输出若干行,每行一个整数,依次表示每个骑士休息的城堡编号。若骑士不可能休息,则输出 -1

     

     

     

    样例输入

    3
    0 1 2
    5
    2 1 3 1 0
    1 2
    2 1 3 1 0
    2 1 3 1 1
    2 1 3 1 2

    样例输出

    2
    -1
    -1
    2

    提示

     

    【数据规模和约定】

     

     

    20%的数据:1 ≤ N, M ≤ 1000

    另有30%的数据:有且仅有一个领主没有下属;

    100%的数据:1 ≤ N, M ≤ 1051 ≤ ai, bi, ci, ki ≤ N0 ≤ yi  <  i 每个事件中 ai ≠ bi

     

     

    来源

    2014北京省选集训day2


    solution

    树剖,转化为区间问题

    对于每一个时间开一棵主席树,下标1~N,表示i是否被毁坏

    对于询问,取出第y棵树和现在的树

    如果有变动,就不能住。

    求第k大就在线段树上二分(就是主席树经典操作)

    比较烦的就是从b到lca的路径要求top-k+1大,

    因为它是倒过来的

    还有ab不能住,需要加一加

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100005
    using namespace std; 
    int n,m,head[maxn],t1,t2,tot,dfn[maxn],deep[maxn],son[maxn],size[maxn];
    int top[maxn],fa[maxn],sc,total,dy[maxn],op,root[maxn],t,a,b;
    int lca,a1,b1,li,ri,rk,las,rak,num1,num2,ff;
    struct no{
        int ls,rs,x;
    }tree[maxn*23];
    struct node{
        int v,nex;
    }e[maxn*2];
    void lj(int t1,int t2){
        total++;e[total].v=t2;e[total].nex=head[t1];head[t1]=total;
    }
    void dfs1(int k,int fath){
        fa[k]=fath;deep[k]=deep[fath]+1;
        int gp=-1,sz=0;
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fath){
                dfs1(e[i].v,k);
                if(gp==-1)gp=e[i].v;
                if(size[e[i].v]>size[gp])gp=e[i].v;
                sz+=size[e[i].v];
            }
        }
        size[k]=sz+1;son[k]=gp;
    }
    void dfs2(int k){
        dfn[k]=++sc;dy[sc]=k;
        if(son[k]!=-1){
            top[son[k]]=top[k];
            dfs2(son[k]);
        }
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fa[k]&&e[i].v!=son[k]){
                top[e[i].v]=e[i].v;
                dfs2(e[i].v);
            }
        }
    }
    void wh(int k){
        tree[k].x=tree[tree[k].ls].x+tree[tree[k].rs].x;
    }
    void dfs(int &k,int la,int l,int r,int pl){
        k=++tot;
        if(l==r){
            tree[k].x=tree[la].x+1;return;
        }
        tree[k].ls=tree[la].ls,tree[k].rs=tree[la].rs;
        int mid=l+r>>1;
        if(pl<=mid)dfs(tree[k].ls,tree[la].ls,l,mid,pl);
        else dfs(tree[k].rs,tree[la].rs,mid+1,r,pl);
        wh(k);
    }
    int ch(int k,int la,int l,int r){
        //cout<<l<<' '<<r<<' '<<li<<' '<<ri<<endl;
        if(l>=li&&r<=ri){
            int tmp=(r-l+1)-(tree[k].x-tree[la].x);
            return tmp;
        }
        int mid=l+r>>1;
        int su=0;
        if(li<=mid)su+=ch(tree[k].ls,tree[la].ls,l,mid);
        if(ri>mid)su+=ch(tree[k].rs,tree[la].rs,mid+1,r);
        return su;
    }
    int ask(int k,int la,int l,int r,int fs){
        //cout<<l<<' '<<r<<' '<<li<<' '<<ri<<endl;
        if(l==r)return dy[l];
        int mid=l+r>>1;
        if(ri>mid){
            int hh=ch(tree[k].rs,tree[la].rs,mid+1,r);
            if(hh>=fs)return ask(tree[k].rs,tree[la].rs,mid+1,r,fs);
            else return ask(tree[k].ls,tree[la].ls,l,mid,fs-hh);
        }
        else return ask(tree[k].ls,tree[la].ls,l,mid,fs);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&t1);
            if(t1==0)continue;
            lj(i,t1);lj(t1,i);
        }
        dfs1(1,0);top[1]=1;dfs2(1);
         
        cin>>m;
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d",&t);
                dfs(root[i],root[i-1],1,n,dfn[t]);
            }
            else {
                root[i]=root[i-1];
                int num=0;
                scanf("%d%d%d%d",&a,&b,&rk,&las);
                li=ri=dfn[a];ff=rk;
                rk+=ch(root[i],root[las],1,n);
                li=ri=dfn[b];
                int fsy=0;
                fsy=ch(root[i],root[las],1,n);
                t1=top[a],t2=top[b];
                a1=a;b1=b;
                while(t1!=t2){
                    if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
                    li=dfn[t1],ri=dfn[a];
                    num+=ch(root[i],root[las],1,n);
                    a=fa[t1],t1=top[a];
                }
                if(deep[a]<deep[b])swap(a,b);
                lca=b;
                li=dfn[b],ri=dfn[a];
                num+=ch(root[i],root[las],1,n);//cout<<"haha "<<rk<<' '<<num<<' '<<rak<<" "<<ff<<" "<<fsy<<endl;
                if(num-fsy<rk){puts("-1");continue;}
                 
                rak=num-rk+1;
                 
                // left
                a=a1;t1=top[a];
                bool fl=0;
                while(t1!=top[lca]){
                    li=dfn[t1],ri=dfn[a];
                    num=ch(root[i],root[las],1,n);
                    if(num>=rk){
                        printf("%d
    ",ask(root[i],root[las],1,n,rk));
                        fl=1;break;
                    }
                    else rk-=num;
                    a=fa[t1],t1=top[a];
                }
                if(fl)continue;
                li=dfn[lca],ri=dfn[a];
                num=ch(root[i],root[las],1,n);
                if(num>=rk){
                    int ans=ask(root[i],root[las],1,n,rk);
                    if(ans==b1)puts("-1");
                    else printf("%d
    ",ans);
                    continue;
                }
                // right
                fl=0;rk=rak;
                b=b1,t2=top[b];
                while(t2!=top[lca]){
                    li=dfn[t2],ri=dfn[b];
                    num=ch(root[i],root[las],1,n);
                    if(num>=rk){
                        printf("%d
    ",ask(root[i],root[las],1,n,rk));
                        fl=1;break;
                    }
                    else rk-=num;
                    b=fa[t2],t2=top[b];
                }
                if(fl)continue;
                li=dfn[lca],ri=dfn[b];
                num=ch(root[i],root[las],1,n);
                if(num>=rk){
                    int ans=ask(root[i],root[las],1,n,rk);
                    if(ans==a1)puts("-1");
                    else printf("%d
    ",ans);
                    continue;
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    纪念又一次ak
    hdu5618
    bzoj3393
    bzoj3438
    [JSOI2007]建筑抢修
    [CQOI2014]数三角形
    [BZOJ2662][BeiJing wc2012]冻结
    [NOIP2015]运输计划
    [ZJOI2006]超级麻将
    [APIO2009]抢掠计划
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358847.html
Copyright © 2020-2023  润新知