JLOI2015 城池攻占

题目链接:戳我

可并堆的一个题目,我写的是左偏树。

我们从下往上面合并,维护一个小根堆,如果在当前节点死亡就弹出,并标记该骑士的终止节点。

这道题和模板不太一样的是还要维护两个标记——add,mul。记得每次调用树上节点值的时候push_down一次!!!

代码如下:

#include<iostream>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define MAXN 300010
using namespace std;
int n,m,tt;
int head[MAXN],rt[MAXN],cnt[MAXN],st[MAXN],en[MAXN],dep[MAXN];

struct knight{int at;long long sum;}kn[MAXN];
struct city{int op,fa;long long val,h;}c[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
struct Node{int ls,rs;long long add,mul,sum,dis;}t[MAXN];

inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}

inline void solve(int x,long long add,long long mul)
{
    t[x].sum*=mul;
    t[x].sum+=add;
    t[x].mul*=mul;
    t[x].add*=mul;
    t[x].add+=add;
}

inline void push_down(int x)
{
    if(t[x].ls) solve(t[x].ls,t[x].add,t[x].mul);
    if(t[x].rs) solve(t[x].rs,t[x].add,t[x].mul);
    t[x].mul=1,t[x].add=0;
}

inline int merge(int x,int y)
{
    if(t[x].sum==-1) x=0;
    if(t[y].sum==-1) y=0;
    if(x==0||y==0) return x+y;
    push_down(x);
    push_down(y);
    if(t[x].sum>t[y].sum) swap(x,y);
    t[x].rs=merge(t[x].rs,y);
    if(t[t[x].ls].dis<t[t[x].rs].dis) swap(t[x].ls,t[x].rs);
    t[x].dis=t[t[x].rs].dis+1;
    return x;
}

inline int pop(int x)
{
    t[x].sum=-1;
    return merge(t[x].ls,t[x].rs);
}

inline void dfs(int x,int pre)
{
    dep[x]=dep[pre]+1;
    for(int i=head[x];i;i=edge[i].nxt) dfs(edge[i].to,x);
    for(int i=head[x];i;i=edge[i].nxt) rt[x]=merge(rt[x],rt[edge[i].to]);
    push_down(rt[x]);
    while(rt[x]&&t[rt[x]].sum<c[x].h)
    {
        push_down(rt[x]);
        cnt[x]++;
        en[rt[x]]=x;
        rt[x]=pop(rt[x]);
    }
    if(c[x].op==1) solve(rt[x],0,c[x].val);
    if(c[x].op==0) solve(rt[x],c[x].val,1);
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&c[i].h);
    for(int i=2;i<=n;i++) scanf("%d%d%lld",&c[i].fa,&c[i].op,&c[i].val),add(c[i].fa,i);
    for(int i=1;i<=m;i++) t[i].add=0,t[i].mul=1;
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%d",&kn[i].sum,&kn[i].at);
        t[i].sum=kn[i].sum;
        st[i]=kn[i].at;
        rt[st[i]]=merge(rt[st[i]],i);
    }
    //for(int i=1;i<=n;i++) printf("%d ",rt[st[i]]); puts("");
    dfs(1,0);
    for(int i=1;i<=n;i++) printf("%d\n",cnt[i]);
    for(int i=1;i<=m;i++) printf("%d\n",dep[st[i]]-dep[en[i]]);
    return 0;
}
posted @ 2019-03-13 16:07  风浔凌  阅读(147)  评论(0编辑  收藏  举报