zoukankan      html  css  js  c++  java
  • [JLOI2015]城池攻占

    [JLOI2015]城池攻占

    题目描述

      小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池。这 n 个城池用 1 到 n 的整数表示。除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi <i。也就是说,所有城池构成了一棵有根树。这 m 个骑士用 1 到 m 的整数表示,其中第 i 个骑士的初始战斗力为 si,第一个攻击的城池为 ci。

      每个城池有一个防御值 hi,如果一个骑士的战斗力大于等于城池的生命值,那么骑士就可以占领这座城池;否则占领失败,骑士将在这座城池牺牲。占领一个城池以后,骑士的战斗力将发生变化,然后继续攻击管辖这座城池的城池,直到占领 1 号城池,或牺牲为止。

      除 1 号城池外,每个城池 i 会给出一个战斗力变化参数 ai;vi。若 ai =0,攻占城池 i 以后骑士战斗力会增加 vi;若 ai =1,攻占城池 i 以后,战斗力会乘以 vi。注意每个骑士是单独计算的。也就是说一个骑士攻击一座城池,不管结果如何,均不会影响其他骑士攻击这座城池的结果。

      现在的问题是,对于每个城池,输出有多少个骑士在这里牺牲;对于每个骑士,输出他攻占的城池数量。

    输入格式:

      第 1 行包含两个正整数 n;m,表示城池的数量和骑士的数量。

      第 2 行包含 n 个整数,其中第 i 个数为 hi,表示城池 i 的防御值。

      第 3 到 n +1 行,每行包含三个整数。其中第 i +1 行的三个数为 fi;ai;vi,分别表示管辖这座城池的城池编号和两个战斗力变化参数。

      第 n +2 到 n + m +1 行,每行包含两个整数。其中第 n + i 行的两个数为 si;ci,分别表示初始战斗力和第一个攻击的城池。 

    输出格式:

       输出 n + m 行,每行包含一个非负整数。其中前 n 行分别表示在城池 1 到 n 牺牲的骑士数量,后 m 行分别表示骑士 1 到 m 攻占的城池数量。

     

    输入样例: 

    5 5
    50 20 10 10 30
    1 1 2
    2 0 5
    2 0 -10
    1 0 10
    20 2
    10 3
    40 4
    20 4
    35 5

    输出样例:

    2
    2
    0
    0
    0
    1
    1
    3
    1
    1

    说明

      对于 100% 的数据,1 <= n;m <= 300000; 1 <= fi<i; 1 <= ci <= n; -10^18 <= hi,vi,si <= 10^18; ai等于1或者0;
      当 ai =1 时,vi > 0;保证任何时候骑士战斗力值的绝对值不超过 10^18。

    思路

      我们看一下题目,题目之中说,如果当前骑士如果攻占了当前的城池,他就会继续前往下一个城池,那么这样我们就可以选择一个可以进行合并的数据结构。继续读题,我们发现如果当前骑士的能力值小于当前的城池,他就会被击杀,这样我们想到可以运用小根堆,这样我们就可以快速杀死所有能力小于城池的骑士。两者结合起来就是可并堆。然而我们依旧需要继续读题,题目之中说了,我们每一次到一个城池,能打下这个城池的所有骑士的能力值都会对应有所改变,如果我们每一次都暴力修改,是不是太慢了?因为修改程度是一样的,所以堆的内部结构不会改变,这样的话,我们可以用一个数组,类似于lazy标记,表示以当前节点为根的堆所有点的变化量,当然这个数组应该由两部分组成,一部分来存乘的数值,另一部分存加的数值。修改就好了。注意先乘后加!!!

    代码

      手写栈的写法(有的oj不开全栈)
    // luogu-judger-enable-o2
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    int order[300001];
    int lson[300001];
    int rson[300001];
    int dis[300001];
    long long need[300001];
    long long num[300001];
    int head[300001];
    int to[300001];
    int nxt[300001];
    long long v[300001];
    int fro[300001];
    int level[300001];
    int ans[300001];
    int ans2[300001];
    bool is[300001];
    long long oper1[300001];
    long long oper2[300001];
    int n,m,idx;
    int str[300001];
    int from[300001];
    void add(int x,int y)
    {
        nxt[++idx]=head[x];
        head[x]=idx;
        to[idx]=y;
    }
    void change(int p)
    {
        num[p]*=oper1[p];
        num[p]+=oper2[p];
        oper1[p]=1;
        oper2[p]=0;
    }
    void pushdown(int p)
    {
        if(lson[p])
        {
            oper1[lson[p]]*=oper1[p];
            oper2[lson[p]]*=oper1[p];
            oper2[lson[p]]+=oper2[p];
        }
        if(rson[p])
        {
            oper1[rson[p]]*=oper1[p];
            oper2[rson[p]]*=oper1[p];
            oper2[rson[p]]+=oper2[p];
        }
        change(p);
    }
    int merge(int x,int y)
    {
        if(!x) return y;
        if(!y) return x;
        pushdown(x);pushdown(y);
        if(num[y]<num[x]) swap(x,y);
        rson[x]=merge(rson[x],y);
        if(dis[rson[x]]>dis[lson[x]])
            swap(lson[x],rson[x]);
        dis[x]=dis[rson[x]]+1;
        return x;
    }
    int check(int pla,int p)
    {
        pushdown(p);
        while(need[pla]>num[p]&&p)
        {
            ans[p]=level[fro[p]]-level[pla];
            p=merge(lson[p],rson[p]);
            ans2[pla]++;
            pushdown(p);
        }
        return p;
    }
    void dfs(int p)
    {
        int l,hed;
        l=idx=0,str[++idx]=p,level[1]=1;
        while(l<idx)
        {
            p=str[++l];
            for(int i=head[p];i;i=nxt[i])
                str[++idx]=to[i],from[idx]=p,level[to[i]]=level[p]+1;
        }
        while(idx)
        {
            p=str[idx];
            order[p]=check(p,order[p]);
            if(is[p]) oper1[order[p]]*=v[p],oper2[order[p]]*=v[p];
            if(!is[p]) oper2[order[p]]+=v[p];
            order[from[idx]]=merge(order[from[idx]],order[p]);
            idx--;
        }/*
        int tmp;
        level[p]=level[from]+1;
        for(int i=head[p];i;i=nxt[i])
            tmp=dfs(to[i],p),order[p]=merge(order[p],tmp);
        order[p]=check(p,order[p]);
        if(is[p]) oper1[order[p]]*=v[p],oper2[order[p]]*=v[p];
        if(!is[p]) oper2[order[p]]+=v[p];
        return order[p];*/
    }
    int main()
    {
        dis[0]=-1;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&need[i]);
        for(int i=2;i<=n;i++)
        {
            int a,b;
            scanf("%d%d%lld",&a,&b,&v[i]);
            add(a,i);
            if(b==1) is[i]=true;
        }
        for(int i=1;i<=m;i++)
        {
            int b;
            oper1[i]=1;
            scanf("%lld%d",&num[i],&b);
            order[b]=merge(order[b],i);
            fro[i]=b;
        }
        dfs(1);
        need[0]=((long long)1e18+1);
        check(0,order[1]);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans2[i]);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
    }
    

      运用系统栈的写法(有的oj开全栈)

    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    int order[300001];
    int lson[300001];
    int rson[300001];
    int dis[300001];
    long long need[300001];
    long long num[300001];
    int head[300001];
    int to[300001];
    int nxt[300001];
    long long v[300001];
    int fro[300001];
    int level[300001];
    int ans[300001];
    int ans2[300001];
    bool is[300001];
    long long oper1[300001];
    long long oper2[300001];
    int n,m,idx;
    int str[300001];
    int from[300001];
    void add(int x,int y)
    {
        nxt[++idx]=head[x];
        head[x]=idx;
        to[idx]=y;
    }
    void change(int p)
    {
        num[p]*=oper1[p];
        num[p]+=oper2[p];
        oper1[p]=1;
        oper2[p]=0;
    }
    void pushdown(int p)
    {
        if(lson[p])
        {
            oper1[lson[p]]*=oper1[p];
            oper2[lson[p]]*=oper1[p];
            oper2[lson[p]]+=oper2[p];
        }
        if(rson[p])
        {
            oper1[rson[p]]*=oper1[p];
            oper2[rson[p]]*=oper1[p];
            oper2[rson[p]]+=oper2[p];
        }
        change(p);
    }
    int merge(int x,int y)
    {
        if(!x) return y;
        if(!y) return x;
        pushdown(x);pushdown(y);
        if(num[y]<num[x]) swap(x,y);
        rson[x]=merge(rson[x],y);
        if(dis[rson[x]]>dis[lson[x]])
            swap(lson[x],rson[x]);
        dis[x]=dis[rson[x]]+1;
        return x;
    }
    int check(int pla,int p)
    {
        pushdown(p);
        while(need[pla]>num[p]&&p)
        {
            ans[p]=level[fro[p]]-level[pla];
            p=merge(lson[p],rson[p]);
            ans2[pla]++;
            pushdown(p);
        }
        return p;
    }
    int dfs(int p,int from)
    {/*
        int l,hed;
        l=idx=0;
        str[++idx]=p;
        while(l<idx)
        {
            p=str[++l];
            for(int i=head[p];i;=nxt[i])
                str[++idx]=p,from[idx]=p;
        }
        while(idx)
        {
            p=str[idx--];
            hed=check(p,order[p]);
            if(is[p]) oper1[hed]*=v[p],oper2[hed]*=v[p];
            if(!is[p]) oper2[hed]+=v[p];
            order[p]=merge()
        }*/
        int tmp;
        level[p]=level[from]+1;
        for(int i=head[p];i;i=nxt[i])
            tmp=dfs(to[i],p),order[p]=merge(order[p],tmp);
        order[p]=check(p,order[p]);
        if(is[p]) oper1[order[p]]*=v[p],oper2[order[p]]*=v[p];
        if(!is[p]) oper2[order[p]]+=v[p];
        return order[p];
    }
    int main()
    {
        dis[0]=-1;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&need[i]);
        for(int i=2;i<=n;i++)
        {
            int a,b;
            scanf("%d%d%lld",&a,&b,&v[i]);
            add(a,i);
            if(b==1) is[i]=true;
        }
        for(int i=1;i<=m;i++)
        {
            int b;
            oper1[i]=1;
            scanf("%lld%d",&num[i],&b);
            order[b]=merge(order[b],i);
            fro[i]=b;
        }
        int hed=dfs(1,0);
        need[0]=((long long)1e18+1);
        check(0,hed);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans2[i]);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    ios UIWebView截获html并修改便签内容(转载)
    IOS获取系统时间 NSDate
    ios 把毫秒值转换成日期 NSDate
    iOS  如何判断当前网络连接状态  网络是否正常  网络是否可用
    IOS开发 xcode报错之has been modified since the precompiled header was built
    iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
    iOS 切图使用 分辨率 使用 相关总结
    整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
    Java面试之PO,VO,TO,QO,BO
    Notes模板说明
  • 原文地址:https://www.cnblogs.com/yangsongyi/p/9046913.html
Copyright © 2011-2022 走看看