• LuoguP3261 [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。注意每个骑士是单独计算的。也就是说一个骑士攻击一座城池,不管结果如何,均不会影响其他骑士攻击这座城池的结果。

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

    在每个节点给骑士挂链,每次合并上来后把所有子树中攻击力小于城市防御力的骑士弹掉。加乘用懒标记。

    pay attention to:

    1、在进行每一操作时要检查那个堆是不是空的,若是即return;

    2、乘时加标记也要乘;

    3、在进行每一操作时要Pushdown;

    4、注意到dfs开始时A赋值为0,这是因为若赋值为u则默认u骑士在u节点,前面“派遣”等赋值为u正因此。
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=3e5+100;
    ll n,m,D[N],v[N],F[N],plu[N],mul[N];
    int h[N],cnt,ls[N],rs[N],ft[N],st[N],d[N],die[N],a[N],dis[N],k[N];
    struct Edge
    {
      int to,next;
    }e[N];
    struct edge
    {
      int to,next;
    }q[N];
    il void add(re int u,re int v)
    {
      e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
    }
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    il void work(re int A,re ll jia,re ll che)
    {
      if(!A) return;//干啥都要注意是否为空堆
      F[A]*=che;F[A]+=jia;
      plu[A]*=che;plu[A]+=jia;mul[A]*=che;//乘时加标记也要乘
    }
    il void Pushdown(re int A)
    {
      work(ls[A],plu[A],mul[A]);
      work(rs[A],plu[A],mul[A]);
      plu[A]=0;mul[A]=1;
    }
    il int Merge(re int A,re int B)
    {
      if(!A||!B) return A+B;
      Pushdown(A);Pushdown(B);//无处不Pushdown
      if(F[A]>F[B]) swap(A,B);
      rs[A]=Merge(rs[A],B);
      if(dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
      dis[A]=dis[rs[A]]+1;
      return A;
    }
    il int Delete(re int A)
    {
      Pushdown(A);
      return Merge(ls[A],rs[A]);
    }
    il int dfs(re int u,re int deep)
    {
      re int A=0;//
      d[u]=deep;
      for(re int i=ft[u];i;i=q[i].next)
        {
          re int v=q[i].to;
          A=Merge(A,v);//每个骑士构出一条链来
        }
      for(re int i=h[u];i;i=e[i].next)
        {
          re int v=e[i].to;
          A=Merge(A,dfs(v,deep+1));
        }
      while(F[A]<D[u]&&A) k[A]=u,++die[u],A=Delete(A);
      if(a[u]) work(A,0,v[u]);else work(A,v[u],1);
      return A;
    }
    int main()
    {
      n=gi();m=gi();
      fp(i,1,n) D[i]=gi();
      fp(i,2,n)
        {
          re int u=gi();a[i]=gi(),v[i]=gi();
          add(u,i);
        }
      cnt=0;
      fp(i,1,m)
        {
          F[i]=gi();st[i]=gi();
          q[++cnt]=(edge){i,ft[st[i]]};ft[st[i]]=cnt;
        }
      dfs(1,1);
      fp(i,1,n) printf("%d ",die[i]);
      fp(i,1,m) printf("%d ",d[st[i]]-d[k[i]]);
      return 0;
    }

  • 相关阅读:
    Blazor client-side + webapi (.net core 3.1) 添加jwt验证流程(非host)第一步
    移动端web框架候选
    Blazor初体验之寻找存储client-side jwt token的方法
    python学习记录(持续更新)--最最最基础的一部分(方法,异常处理,注释,类)
    python学习记录(持续更新)--最最最基础的一部分(条件分支、循环、数组矩阵、元组)
    python学习记录(持续更新)--最最最基础的一部分(变量、字符串、运算符、常见函数)
    C#后台异步消息队列实现
    Quartz.Net 删除一个Job
    授权认证(IdentityServer4)
    文件同步
  • 原文地址:https://www.cnblogs.com/yanshannan/p/8462527.html
Copyright © 2020-2023  润新知