zoukankan      html  css  js  c++  java
  • bzoj 4003 [JLOI2015]城池攻占 —— 左偏树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4003

    其实蛮简单的,首先一个城市只会被其子树中的骑士经过,启发我们 dfs 序用可并堆合并子树信息;

    先乘后加,和带乘法的线段树一个方法;

    如果秒 WA 的话,把读入全写成 %lld 就好了...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const maxn=3e5+5;
    int n,m,c[maxn],rt[maxn],a[maxn],dis[maxn],dep[maxn];
    ll h[maxn],v[maxn],s[maxn],la[maxn],lc[maxn];
    int hd[maxn],ct,to[maxn],nxt[maxn],ans[maxn],end[maxn],ls[maxn],rs[maxn];
    void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
    void update(int x,ll c,ll a)
    {
        if(!x)return;//
        s[x]*=c; s[x]+=a;
        lc[x]*=c; la[x]*=c; la[x]+=a;
    }
    void pushdown(int x)
    {
        if(lc[x]==1&&la[x]==0)return;//
        update(ls[x],lc[x],la[x]); update(rs[x],lc[x],la[x]);
        lc[x]=1; la[x]=0;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        pushdown(x); pushdown(y);//
        if(s[x]>s[y])swap(x,y);
        rs[x]=merge(rs[x],y);
        if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]);
        if(rs[x])dis[x]=dis[rs[x]]+1;
        else dis[x]=0;
        return x;
    }
    void dfs(int x,int f)
    {
        dep[x]=dep[f]+1; 
        pushdown(rt[x]);
        for(int i=hd[x],u;i;i=nxt[i])
        {
            dfs(u=to[i],x); pushdown(rt[u]);
            rt[x]=merge(rt[x],rt[u]);
        }
        while(rt[x]&&s[rt[x]]<h[x])
        {
            pushdown(rt[x]);
            ans[x]++; end[rt[x]]=x;
            rt[x]=merge(ls[rt[x]],rs[rt[x]]);
        }
        if(a[x]==0)update(rt[x],1,v[x]);
        else update(rt[x],v[x],0);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld",&h[i]);
        for(int i=2,fa;i<=n;i++)scanf("%lld%lld%lld",&fa,&a[i],&v[i]),add(fa,i);
        for(int i=1;i<=m;i++)lc[i]=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%lld%lld",&s[i],&c[i]);
            rt[c[i]]=merge(rt[c[i]],i);
    //        lc[i]=1;
        }
        dfs(1,0);
        for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
        for(int i=1;i<=m;i++)printf("%d
    ",dep[c[i]]-dep[end[i]]);
        return 0;
    }
  • 相关阅读:
    洛谷P5304 [GXOI/GZOI2019]旅行者
    洛谷P3758 [TJOI2017]可乐
    洛谷P5341 [TJOI2019]甲苯先生和大中锋的字符串
    洛谷P5338 [TJOI2019]甲苯先生的滚榜
    洛谷P5340 [TJOI2019]大中锋的游乐场
    AC自动机
    左偏树(可并堆)实现
    splay区间翻转
    平衡树模板【splay的实现】
    洛谷P4113 [HEOI2012]采花
  • 原文地址:https://www.cnblogs.com/Zinn/p/9599193.html
Copyright © 2011-2022 走看看