BZOJ4003 [JLOI2015]城池攻占

来源:互联网 发布:杀女婴知乎 编辑:程序博客网 时间:2024/05/17 07:32

4003: [JLOI2015]城池攻占
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1266 Solved: 472
[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。


打标记的可并堆。
随机堆有时比左偏树慢,有时快。

左偏树

#include <bits/stdc++.h>#define N 300010#define ll long long#define ld long doubleusing namespace std;int n,m,fa[N],a[N],c[N],fir[N],nxt[N<<1],to[N<<1],tot(1),dep[N],ans[N],num[N];ll h[N],v[N],s[N];vector<int> p[N];template <class Aqua>inline void read(Aqua &s){    s=0; Aqua f=1; char c=getchar();    while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}    while (isdigit(c)) s=s*10+c-'0',c=getchar();    s*=f;}struct heap{    heap *ch[2],*fa;    int dep,h,id; ll tag,tag_,x;    inline void times(ll d){        x*=d,tag*=d,tag_*=d;    }    inline void add(ll d){        x+=d,tag_+=d;    }    inline void pushdown(){        if (ch[0])            ch[0]->times(tag),ch[0]->add(tag_);        if (ch[1])            ch[1]->times(tag),ch[1]->add(tag_);        tag=1; tag_=0;    }    friend heap *merge(heap *a,heap *b){        #define height(p) ((p)?p->h:0)        if (!a) return b;        if (!b) return a;        if (a->x>b->x)            swap(a,b);        a->pushdown();        a->ch[1]=merge(a->ch[1],b);        if (height(a->ch[1])>height(a->ch[0]))            swap(a->ch[0],a->ch[1]);        a->h=height(a->ch[1])+1;        return a;    }    heap *pop(){        this->pushdown();        return merge(ch[0],ch[1]);    }}pool[N],*tail=pool;heap *newnode(ll x,int d){    tail->x=s[x],tail->id=x,tail->dep=d;    tail->h=tail->tag=1; tail->tag_=0;    tail->ch[0]=tail->ch[1]=0;    return tail++;}inline void add(int u,int v){    to[++tot]=v; nxt[tot]=fir[u]; fir[u]=tot;}heap *dfs(int x){    dep[x]=dep[fa[x]]+1;    heap *cur=0;    for (int i=0;i<p[x].size();i++)        cur=merge(cur,newnode(p[x][i],dep[x]));    for (int i=fir[x];i;i=nxt[i])        if (to[i]!=fa[x])            cur=merge(cur,dfs(to[i]));    for (;cur && cur->x<h[x];cur=cur->pop()){        cur->pushdown();        num[cur->id]=cur->dep-dep[x];        ans[x]++;    }    if (cur)        (a[x]?cur->times(v[x]):cur->add(v[x]));    return cur;}int main(){    read(n),read(m);    for (int i=1;i<=n;i++)        read(h[i]);    for (int i=2;i<=n;i++){        read(fa[i]),read(a[i]),read(v[i]);        add(i,fa[i]),add(fa[i],i);    }    for (int i=1;i<=m;i++){        read(s[i]),read(c[i]);        p[c[i]].push_back(i);    }    heap *cur=dfs(1);    for (;cur;cur=cur->pop()){        cur->pushdown();        num[cur->id]=cur->dep;    }    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]);    for (int i=1;i<=m;i++)        printf("%d\n",num[i]);    return 0;}

随机堆

#include <bits/stdc++.h>#define N 300010#define ll long long#define ld long doubleusing namespace std;int n,m,fa[N],a[N],c[N],fir[N],nxt[N<<1],to[N<<1],tot(1),dep[N],ans[N],num[N];ll h[N],v[N],s[N];vector<int> p[N];template <class Aqua>inline void read(Aqua &s){    s=0; Aqua f=1; char c=getchar();    while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}    while (isdigit(c)) s=s*10+c-'0',c=getchar();    s*=f;}struct heap{    heap *ch[2],*fa;    int dep,id; ll tag,tag_,x;    inline void times(ll d){        x*=d,tag*=d,tag_*=d;    }    inline void add(ll d){        x+=d,tag_+=d;    }    inline void pushdown(){        if (ch[0])            ch[0]->times(tag),ch[0]->add(tag_);        if (ch[1])            ch[1]->times(tag),ch[1]->add(tag_);        tag=1; tag_=0;    }    friend heap *merge(heap *a,heap *b){        if (!a) return b;        if (!b) return a;        if (a->x>b->x)            swap(a,b);        a->pushdown();        int x=rand()&1;        a->ch[x]=merge(a->ch[x],b);        return a;    }    heap *pop(){        this->pushdown();        return merge(ch[0],ch[1]);    }}pool[N],*tail=pool;heap *newnode(ll x,int d){    tail->x=s[x],tail->id=x,tail->dep=d;    tail->tag=1; tail->tag_=0;    tail->ch[0]=tail->ch[1]=0;    return tail++;}inline void add(int u,int v){    to[++tot]=v; nxt[tot]=fir[u]; fir[u]=tot;}heap *dfs(int x){    dep[x]=dep[fa[x]]+1;    heap *cur=0;    for (int i=0;i<p[x].size();i++)        cur=merge(cur,newnode(p[x][i],dep[x]));    for (int i=fir[x];i;i=nxt[i])        if (to[i]!=fa[x])            cur=merge(cur,dfs(to[i]));    for (;cur && cur->x<h[x];cur=cur->pop()){        cur->pushdown();        num[cur->id]=cur->dep-dep[x];        ans[x]++;    }    if (cur)        (a[x]?cur->times(v[x]):cur->add(v[x]));    return cur;}int main(){    srand(time(NULL));    read(n),read(m);    for (int i=1;i<=n;i++)        read(h[i]);    for (int i=2;i<=n;i++){        read(fa[i]),read(a[i]),read(v[i]);        add(i,fa[i]),add(fa[i],i);    }    for (int i=1;i<=m;i++){        read(s[i]),read(c[i]);        p[c[i]].push_back(i);    }    heap *cur=dfs(1);    for (;cur;cur=cur->pop()){        cur->pushdown();        num[cur->id]=cur->dep;    }    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]);    for (int i=1;i<=m;i++)        printf("%d\n",num[i]);    return 0;}