[BZOJ4003][JLOI2015]城池攻占

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4003][JLOI2015]城池攻占相关的知识,希望对你有一定的参考价值。

BZOJ
Luogu

sol

左偏树
骑士对于树上结点挂链,每次合并所有子树上的骑士后把所有攻击力小于城池防御值的骑士弹掉。
左偏树维护加乘懒标记
记得要pushdown
delete的时候也要记得pushdown!

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int MAX=300005;
struct edge{int to,next;}a[MAX],b[MAX];
int head[MAX],cnt,ft[MAX];
bool type[MAX];
ll h[MAX],key[MAX],v[MAX],plu[MAX],mul[MAX];
int n,m,ls[MAX],rs[MAX],dis[MAX],str[MAX],dep[MAX],dead[MAX],up[MAX];
ll gi()
{
    ll x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=-1,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*w;
}
void cover(int A,ll c,ll j)
{
    if (!A) return;
    key[A]*=c;key[A]+=j;
    mul[A]*=c;plu[A]*=c;plu[A]+=j;
}
void pushdown(int A)
{
    cover(ls[A],mul[A],plu[A]);
    cover(rs[A],mul[A],plu[A]);
    mul[A]=1;plu[A]=0;
}
int merge(int A,int B)
{
    if (!A||!B) return A+B;
    if (key[A]>key[B]) swap(A,B);
    pushdown(A);pushdown(B);
    rs[A]=merge(rs[A],B);
    if (dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
    dis[A]=dis[rs[A]]+1;
    return A;
}
int del(int A)
{
    pushdown(A);
    return merge(ls[A],rs[A]);
}
int dfs(int u,int f)
{
    dep[u]=dep[f]+1;
    int A=0,B;
    for (int e=ft[u];e;e=b[e].next) A=merge(A,b[e].to);
    for (int e=head[u];e;e=a[e].next)
    {
        int v=a[e].to;
        B=dfs(v,u);
        A=merge(A,B);
    }
    while (key[A]<h[u]&&A)
    {
        up[A]=dep[u];++dead[u];
        A=del(A);
    }
    if (type[u]) cover(A,v[u],0);
    else cover(A,1,v[u]);
    return A;
}
int main()
{
    n=gi();m=gi();
    for (int i=1;i<=n;i++) h[i]=gi();
    for (int i=2,u;i<=n;i++)
    {
        u=gi();
        a[++cnt]=(edge){i,head[u]};head[u]=cnt;
        type[i]=gi();v[i]=gi();
    }
    cnt=0;
    for (int i=1;i<=m;i++)
    {
        key[i]=gi();str[i]=gi();
        b[++cnt]=(edge){i,ft[str[i]]};ft[str[i]]=cnt;
    }
    dfs(1,0);
    for (int i=1;i<=n;i++) printf("%d\n",dead[i]);
    for (int j=1;j<=m;j++) printf("%d\n",dep[str[j]]-up[j]);
    return 0;
}

以上是关于[BZOJ4003][JLOI2015]城池攻占的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4003JLOI2015城池攻占

[BZOJ4003][JLOI2015]城池攻占

bzoj4003[JLOI2015]城池攻占 可并堆

BZOJ4003 JLOI2015城池攻占

bzoj4003: [JLOI2015]城池攻占 左偏树

BZOJ 4003: [JLOI2015]城池攻占 左偏树 可并堆