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

    题解:可并堆 类似线段树维护两个标记(乘法系数和加法系数) 然后从低到上逐渐弹出元素并维护可并堆的同时维护答案  注意元素弹完的情况

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    typedef struct node{
        int ch[2],sz,dis,flag3;ll key,flag1,flag2;
    }node;
    
    node d[MAXN];
    void newnode(int x,ll t){
        d[x].ch[0]=d[x].ch[1]=d[x].sz=d[x].dis=d[x].flag3=d[x].flag2=0;
        d[x].key=t;d[x].flag1=1;
    }
    void Flag1(int x,ll t){
        if(!x)return ;
        d[x].flag1*=t;d[x].flag2*=t;
        d[x].key*=t;
    }
    
    void Flag2(int x,ll t){
        if(!x)return ;
        d[x].key+=t;d[x].flag2+=t;
    }
    void Flag3(int x,int t){
        if(!x)return ;
        d[x].sz+=t;d[x].flag3+=t;
    }
    
    void push(int x){
        if(d[x].flag1!=1){
    	if(d[x].ch[0])Flag1(d[x].ch[0],d[x].flag1);
    	if(d[x].ch[1])Flag1(d[x].ch[1],d[x].flag1);
    	d[x].flag1=1;
        }
        if(d[x].flag2){
    	if(d[x].ch[0])Flag2(d[x].ch[0],d[x].flag2);
    	if(d[x].ch[1])Flag2(d[x].ch[1],d[x].flag2);
    	d[x].flag2=0;
        }
        if(d[x].flag3){
    	if(d[x].ch[0])Flag3(d[x].ch[0],d[x].flag3);
    	if(d[x].ch[1])Flag3(d[x].ch[1],d[x].flag3);
    	d[x].flag3=0;
        }
    }
    
    int merge(int x,int y){
        if(!x||!y)return x+y;
        push(x);push(y);
        if(d[x].key>d[y].key)swap(x,y);
        d[x].ch[1]=merge(d[x].ch[1],y);
        if(d[d[x].ch[0]].dis<d[d[x].ch[1]].dis)swap(d[x].ch[0],d[x].ch[1]);
        d[x].dis=d[d[x].ch[1]].dis+1;
        return x;
    }
    
    int rt[MAXN];
    ll H[MAXN],V[MAXN];
    int op[MAXN];
    int num[MAXN];
    
    void dfs(int x){
        link(x){
    	dfs(j->t);
    	rt[x]=merge(rt[x],rt[j->t]);
        }
        while(rt[x]&&d[rt[x]].key<H[x]){
    	num[x]++;
    	push(rt[x]);
    	rt[x]=merge(d[rt[x]].ch[0],d[rt[x]].ch[1]);
        }
        if(x!=1){
    	if(op[x])Flag1(rt[x],V[x]);
    	else Flag2(rt[x],V[x]);
        }
        if(rt[x])Flag3(rt[x],1);
    }
    
    int main(){
        int n=read();int m=read();
        inc(i,1,n)H[i]=read();
        int u;
        inc(i,2,n)u=read(),add(u,i),op[i]=read(),V[i]=read();
        ll k;
        inc(i,1,m)k=read(),newnode(i,k),u=read(),rt[u]=merge(rt[u],i);
        dfs(1);
        while(rt[1]){
    	push(rt[1]);
    	rt[1]=merge(d[rt[1]].ch[0],d[rt[1]].ch[1]);
        }
        inc(i,1,n)printf("%d
    ",num[i]);
        inc(i,1,m)printf("%d
    ",d[i].sz);
    }
    

      

      

    4003: [JLOI2015]城池攻占

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1984  Solved: 846
    [Submit][Status][Discuss]

    Description

    小铭铭最近获得了一副新的桌游,游戏中需要用 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。注意每个骑士是单独计算的。也就是说一个骑士攻击一座城池,不管结果如何,均不会影响其他骑士攻击这座城池的结果。
    现在的问题是,对于每个城池,输出有多少个骑士在这里牺牲;对于每个骑士,输出他攻占的城池数量。

    Input

    第 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,分别表
    示初始战斗力和第一个攻击的城池。

    Output

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

    数量,后 m 行分别表示骑士 1 到 m 攻占的城池数量。

    Sample Input

    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

    Sample Output

    2
    2
    0
    0
    0
    1
    1
    3
    1
    1

    HINT

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

  • 相关阅读:
    OPPO R9sPlus MIFlash线刷TWRP Recovery ROOT详细教程
    OPPO R11 R11plus系列 解锁BootLoader ROOT Xposed 你的手机你做主
    努比亚(nubia) M2青春版 NX573J 解锁BootLoader 并进入临时recovery ROOT
    华为 荣耀 等手机解锁BootLoader
    青橙 M4 解锁BootLoader 并刷入recovery ROOT
    程序员修炼之道阅读笔03
    冲刺8
    典型用户模板分析
    学习进度八
    冲刺7
  • 原文地址:https://www.cnblogs.com/wang9897/p/10333809.html
Copyright © 2011-2022 走看看