bzoj 4003: [JLOI2015]城池攻占 左偏树

来源:互联网 发布:怎样注册淘宝买家号 编辑:程序博客网 时间:2024/04/28 13:13

题意

小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池。
这 n 个城池用 1 到 n 的整数表示。除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,
其中 fi

分析

一开始的想法是倍增,据说可以过但是好麻烦。
看了题解发现原来可以用数据结构来做,就是像线段树合并那样从底下往上做,期间打打标记啥的就好了。
左偏树平衡树什么的都很资瓷啊。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=300005;int n,m,num[N],ans[N],dep[N],cnt,last[N],c[N],a[N],root[N];LL h[N],v[N];struct edge{int to,next;}e[N];struct tree{int l,r,dis;LL val,tag1,tag2;}t[N];void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;}void pushdown(int d){    LL u=t[d].tag1,v=t[d].tag2;t[d].tag1=1;t[d].tag2=0;    if (t[d].l) t[t[d].l].val=t[t[d].l].val*u+v,t[t[d].l].tag1*=u,t[t[d].l].tag2=t[t[d].l].tag2*u+v;    if (t[d].r) t[t[d].r].val=t[t[d].r].val*u+v,t[t[d].r].tag1*=u,t[t[d].r].tag2=t[t[d].r].tag2*u+v;}int merge(int x,int y){    if (!x||!y) return x+y;    pushdown(x);pushdown(y);    if (t[x].val>t[y].val) swap(x,y);    t[x].r=merge(t[x].r,y);    if (t[t[x].l].dis<t[t[x].r].dis) swap(t[x].l,t[x].r);    t[x].dis=t[t[x].l].dis+1;    return x;}void get_dep(int x,int fa){    dep[x]=dep[fa]+1;    for (int i=last[x];i;i=e[i].next) get_dep(e[i].to,x);}void solve(int x){    for (int i=last[x];i;i=e[i].next)    {        solve(e[i].to);        if (a[e[i].to]==0) t[root[e[i].to]].val+=v[e[i].to],t[root[e[i].to]].tag2+=v[e[i].to];        else t[root[e[i].to]].val*=v[e[i].to],t[root[e[i].to]].tag1*=v[e[i].to],t[root[e[i].to]].tag2*=v[e[i].to];        root[x]=merge(root[x],root[e[i].to]);    }    while (root[x]&&t[root[x]].val<h[x]) ans[root[x]]=x,pushdown(root[x]),root[x]=merge(t[root[x]].l,t[root[x]].r),num[x]++;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%lld",&h[i]);    for (int i=2;i<=n;i++)    {        int x;        scanf("%d%lld%lld",&x,&a[i],&v[i]);        addedge(x,i);    }    for (int i=1;i<=m;i++)    {        LL s;        scanf("%lld%d",&s,&c[i]);        t[i].val=s;t[i].tag1=1;        root[c[i]]=merge(root[c[i]],i);    }    get_dep(1,0);    solve(1);    for (int i=1;i<=n;i++) printf("%d\n",num[i]);    for (int i=1;i<=m;i++) printf("%d\n",dep[c[i]]-dep[ans[i]]);    return 0;}
0 0