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]);
    }
  • 相关阅读:
    C++---继承和派生
    【解迷糊】关于PHP的extract()函数提取出的变量的作用域问题
    PHP常用内置函数记忆(持更)
    PHP数据类型转换
    在window把自己的项目上传到github
    github Desktop上传项目
    【终于明白】PHP加入命名空间的好处--方便自动加载
    PHP中session的使用方法和生命周期问题
    php
    PHP中include和require的区别详解
  • 原文地址:https://www.cnblogs.com/yangsongyi/p/9046913.html
Copyright © 2011-2022 走看看