• 【左偏树+延迟标记+拓扑排序】BZOJ4003-城池攻占


    【题目大意】

    有n个城市构成一棵树,除1号城市外每个城市均有防御值h和战斗变化参量a和v。

    现在有m个骑士各自来刷副本,每个其实有一个战斗力s和起始位置c。如果一个骑士的战斗力s大于当前城市的防御值h,则可攻破这个城市,并前往它的管辖地(即树上的父亲),同时,战斗力s发生如下变化:

    ①如被攻占城市a=0,则s+=v;

    ②如果a=0,s*=v。

    输出:每个骑士能够攻占的城市数量,以及每个城市有多少个骑士牺牲了。

    【思路】

    昨天写了一遍这道题,当时用的是DFS,今天用拓扑重写一遍。思路如下:

    从下往上拓扑排序,左偏树里存放骑士。当前节点上的左偏树相当于可以存活到当前城市的所有骑士的集合,存放在一个小顶堆中。显然,如果较小的骑士能攻破,那么较大的一定能。那么每次,如果堆顶小于当前城市的防御值,则弹出。每个城市攻占结束后,更新一下所有骑士们的战斗力。

    左偏树和其它树型结构一样,都可以使用延迟标记。做法和线段树差不多。

    延迟标记有三个,lazycnt,lazyadd,lazymul,分别表示攻占城市数的增加和战斗力的增加。更新操作时,将左右孩子的cnt和lazycnt均加上当前的lazycnt。如果当前a=0,则将左右孩子的key和lazyadd加上当前的lazyadd;如果当前a=1,则将左右孩子的key、lazymul和lazyadd均乘以当前的lazymul。

    延迟标记在两个地方需要往下推:

    ①在堆顶元素弹出后。

    在merge中将较小根的右子树和较大根的左子树合并的时候。(!!!)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<queue>
      7 #define L Ltree[Ltree[x].lson]
      8 #define R Ltree[Ltree[x].rson]
      9 using namespace std;
     10 typedef long long ll;
     11 const int MAXN=300000+50;
     12 struct node
     13 {
     14     ll key;
     15     int dis,pos,cnt;
     16     ll lazyadd,lazymul;int lazycnt;//懒惰标记
     17     int lson,rson; 
     18 };
     19 int n,m;
     20 ll h[MAXN],v[MAXN];//防御力,战斗变化量,
     21 int city[MAXN],knight[MAXN],f[MAXN],a[MAXN],out[MAXN],rt[MAXN];
     22 //每个城市牺牲的骑士数,每个骑士攻破的城市数量,管辖地,战斗变化参数,每个节点的出度(拓扑排序使用),到达每个节点位置时的堆顶元素 
     23 node Ltree[MAXN];//左偏树 
     24 queue<int> que;//树由下至上拓扑排序的队列 
     25 
     26 void update(int root,int flag,ll delta)
     27 {
     28     Ltree[root].lazycnt++;
     29     Ltree[root].cnt++;
     30     if (flag)
     31     {
     32         Ltree[root].lazyadd*=delta;
     33         Ltree[root].lazymul*=delta;
     34         Ltree[root].key*=delta;
     35     }
     36     else
     37     {
     38         Ltree[root].lazyadd+=delta;
     39         Ltree[root].key+=delta;
     40     }
     41 }
     42 
     43 void pushdown(int x)
     44 {
     45     if (Ltree[x].lazycnt)
     46     {
     47         L.cnt+=Ltree[x].lazycnt;
     48         R.cnt+=Ltree[x].lazycnt;
     49         L.lazycnt+=Ltree[x].lazycnt;
     50         R.lazycnt+=Ltree[x].lazycnt;
     51         Ltree[x].lazycnt=0;
     52     }
     53     if (Ltree[x].lazymul!=1)
     54     {
     55         L.key*=Ltree[x].lazymul;
     56         R.key*=Ltree[x].lazymul;
     57         L.lazyadd*=Ltree[x].lazymul;
     58         R.lazyadd*=Ltree[x].lazymul;
     59         L.lazymul*=Ltree[x].lazymul;
     60         R.lazymul*=Ltree[x].lazymul;
     61         Ltree[x].lazymul=1;
     62     } 
     63     if (Ltree[x].lazyadd)
     64     {
     65         L.key+=Ltree[x].lazyadd;
     66         R.key+=Ltree[x].lazyadd;
     67         L.lazyadd+=Ltree[x].lazyadd;
     68         R.lazyadd+=Ltree[x].lazyadd;
     69         Ltree[x].lazyadd=0;
     70     }
     71 }
     72 
     73 int merge(int x,int y)
     74 {
     75     if (!x||!y) 
     76     {
     77         return(x+y);
     78     }
     79     if (Ltree[x].key>Ltree[y].key) swap(x,y);
     80     pushdown(x);
     81     //!!!这里要pushdown!!这里千万不要忘记pushdown! 
     82     Ltree[x].rson=merge(Ltree[x].rson,y);
     83     int &l=Ltree[x].lson,&r=Ltree[x].rson;
     84     if (Ltree[l].dis<Ltree[r].dis) swap(l,r);
     85     if (r==0) Ltree[x].dis=0;
     86         else Ltree[x].dis=Ltree[r].dis+1;
     87     return x;
     88 }
     89  
     90 void init()
     91 {
     92     scanf("%d%d",&n,&m);
     93     memset(rt,0,sizeof(rt));
     94     for (int i=1;i<=n;i++) scanf("%lld",&h[i]);
     95     for (int i=2;i<=n;i++) 
     96     {
     97         scanf("%d%d%lld",&f[i],&a[i],&v[i]);
     98         out[f[i]]++;
     99     }
    100     Ltree[0].dis=-1;
    101     for (int i=1;i<=m;i++)
    102     {
    103         ll s;int c;
    104         scanf("%lld%d",&s,&c);
    105         Ltree[i]=(node){s,0,i,0,0,1,0};
    106         rt[c]=merge(rt[c],i);
    107     }
    108 }
    109 
    110 void Topology()
    111 {
    112     queue<int> que;
    113     for (int i=1;i<=n;i++) if (!out[i]) que.push(i);
    114     while (!que.empty())
    115     {
    116         int u=que.front();que.pop();
    117         int& root=rt[u];
    118         int father=f[u];
    119         while (root && (h[u]>Ltree[root].key))//如果堆顶元素小于城市的防御力,即该骑士会牺牲,则不断弹出 
    120         {
    121             knight[Ltree[root].pos]=Ltree[root].cnt;
    122             city[u]++;
    123             pushdown(root);
    124             root=merge(Ltree[root].lson,Ltree[root].rson);
    125         }
    126         update(root,a[u],v[u]);
    127         rt[father]=merge(rt[father],root);
    128         out[father]--;
    129         if (!out[father]) que.push(father);
    130     }
    131     
    132     while (rt[1])//处理所有能够抵达根节点的所有骑士 
    133     {
    134         knight[rt[1]]=Ltree[rt[1]].cnt;
    135         pushdown(rt[1]);
    136         rt[1]=merge(Ltree[rt[1]].lson,Ltree[rt[1]].rson);
    137     } 
    138 }
    139 
    140 void printans()
    141 {
    142     for (int i=1;i<=n;i++) printf("%d
    ",city[i]);
    143     for (int j=1;j<=m;j++) printf("%d
    ",knight[j]);
    144 }
    145 
    146 int main()
    147 {
    148     init();
    149     Topology();
    150     printans();
    151     return 0;
    152 }
  • 相关阅读:
    this.props.children 踩坑
    3.webpack配置
    2.项目初始化配置
    1项目库的建立
    Idea-代码背景设置
    SpringBoot+nacos-环境切换-配置文件
    Docker-镜像地址无法访问
    端口-映射、开放、定义
    Linux-命令
    Nginx-命令
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5687873.html
Copyright © 2020-2023  润新知