• 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
    ",cnt[i]);
        for(int i=1;i<=m;i++) printf("%d
    ",dep[st[i]]-dep[en[i]]);
        return 0;
    }
    
  • 相关阅读:
    第二天课程档案
    第一天课程档案
    SAM初步
    计算几何初步
    数论二次总结
    生成函数入门题汇总
    1500: [NOI2005]维修数列
    20170214
    【bzoj2286】[Sdoi2011]消耗战
    bzoj2223: [Coci 2009]PATULJCI
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10522448.html
Copyright © 2020-2023  润新知