BZOJ 4003 JLOI2015 城池攻占

做法和APIO2012派遣 那道题目类似

在树上DFS,维护当前子树的小根堆

因为需要合并孩子们的信息,使用左偏树就可以了

每次弹出死亡骑士,对剩余骑士打上奖励标记

至于标记的下传和更改,只需要每次在需要遍历到这个点之前push_down就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
 
typedef long long LL;
const int maxn=300010;
int n,m;
int a[maxn],rt[maxn],fa[maxn],c[maxn];
int ans1[maxn],ans2[maxn];
LL f[maxn],k[maxn],b[maxn],s[maxn];
int h[maxn],cnt=0;
int dep[maxn];
struct edge{
    int to,next;
}G[maxn];
struct Tree{
    int L,R,dis;
    LL v,k,b;
}t[maxn];
void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
void Get_mark(int a,LL k,LL b){
    if(a==0)return;
    t[a].v=t[a].v*k+b;
    t[a].k*=k;t[a].b*=k;t[a].b+=b;
}
void push_down(int a){
    Get_mark(t[a].L,t[a].k,t[a].b);
    Get_mark(t[a].R,t[a].k,t[a].b);
    t[a].k=1;t[a].b=0;
}
int merge(int a,int b){
    if(!a||!b)return a+b;
    push_down(a);push_down(b);
    if(t[a].v>t[b].v)swap(a,b);
    t[a].R=merge(t[a].R,b);
    if(t[t[a].R].dis>t[t[a].L].dis)swap(t[a].L,t[a].R);
    t[a].dis=t[t[a].R].dis+1;
    return a;
}
void DFS(int u){
    for(int i=h[u];i;i=G[i].next){
        int v=G[i].to;
        dep[v]=dep[u]+1;
        DFS(v);
        Get_mark(rt[v],k[v],b[v]);
        rt[u]=merge(rt[u],rt[v]);
    }
    while(rt[u]&&t[rt[u]].v<f[u]){
        push_down(rt[u]);ans1[u]++;
        ans2[rt[u]]=dep[c[rt[u]]]-dep[u];
        rt[u]=merge(t[rt[u]].L,t[rt[u]].R);
    }return;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%lld",&f[i]);
    for(int i=2;i<=n;++i){
        scanf("%d%lld%lld",&fa[i],&k[i],&b[i]);
        if(k[i]==0)k[i]=1;
        else k[i]=b[i],b[i]=0;
        add(fa[i],i);
    }
    for(int i=1;i<=m;++i){
        scanf("%lld%d",&s[i],&c[i]);
        t[i].v=s[i];t[i].k=1;t[i].b=0;
        rt[c[i]]=merge(rt[c[i]],i);
    }
    DFS(1);
    while(rt[1]){
        push_down(rt[1]);
        ans2[rt[1]]=dep[c[rt[1]]]+1;
        rt[1]=merge(t[rt[1]].L,t[rt[1]].R);
    }
    for(int i=1;i<=n;++i)printf("%d\n",ans1[i]);
    for(int i=1;i<=m;++i)printf("%d\n",ans2[i]);
    return 0;
     
}

  

 

posted @ 2016-04-14 20:24  _Vertical  阅读(257)  评论(0编辑  收藏  举报