[JLOI2015] 城池攻占

题目描述:

雾.

题目分析:

改变操作乘法是没有负数的,那么就不会改变大小关系,我们就可以DFS树,然后用可合并堆进行操作。
Splay+启发式合并也可以过

题目链接:

Luogu 3261
BZOJ 4003

Ac 代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
const int maxm=310000;
struct left_tree{
    int adi,adx;
    int dis,ls,rs,fa;
    int v;
}st[maxm];
int begin[maxm],end[maxm],dead[maxm],deep[maxm];
int rt[maxm];
int flag[maxm],v[maxm],d[maxm];
int n,m;
int head[maxm],net[maxm],to[maxm],cnt;
inline void addedge(int u,int v)
{
    cnt++;
    to[cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
inline void col(int o,int addi,int addx)
{
    if(!o) return;
    //printf("-1:%d-\n",st[o].v);
    st[o].v*=addx;
    //printf("-2:%d-\n",st[o].v);
    st[o].v+=addi;
    //printf("-3:%d-\n",st[o].v);
    st[o].adi*=addx,st[o].adx*=addx;
    st[o].adi+=addi;
}
inline void pushdown(int o)
{
    col(st[o].ls,st[o].adi,st[o].adx);
    col(st[o].rs,st[o].adi,st[o].adx);
    st[o].adi=0,st[o].adx=1;
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    pushdown(x),pushdown(y);
    if(st[x].v>st[y].v||(st[x].v==st[y].v&&x>y))
     std::swap(x,y); 
    st[x].rs=merge(st[x].rs,y);
    st[st[x].rs].fa=x;
    if(st[st[x].ls].dis<st[st[x].rs].dis) std::swap(st[x].ls,st[x].rs);
    st[x].dis=st[st[x].rs].dis+1;
    return x;
}
inline int pop(int o)
{
    return merge(st[o].ls,st[o].rs);
}
void dfs(int now,int fa)
{
    deep[now]=deep[fa]+1;
    for(int i=head[now];i;i=net[i])
    if(to[i]!=fa)
     dfs(to[i],now);
    for(int i=head[now];i;i=net[i])
     if(to[i]!=fa)
      rt[now]=merge(rt[now],rt[to[i]]);
    //printf("%d %d %d\n",now,st[rt[now]].v,d[now]);
    while(rt[now]&&st[rt[now]].v<d[now])
    {
        pushdown(rt[now]);
        dead[now]++;
        end[rt[now]]=now;
        rt[now]=pop(rt[now]);
    } 
    if(!flag[now]) col(rt[now],v[now],1);
    else col(rt[now],0,v[now]);
}
main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&d[i]);
    for(int i=2;i<=n;i++)
    {
        int fax;
        scanf("%lld%lld%lld",&fax,&flag[i],&v[i]);
        addedge(fax,i);
    }
    for(int i=1;i<=m;i++) st[i].adi=0,st[i].adx=1;
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&st[i].v,&begin[i]);
        rt[begin[i]]=merge(rt[begin[i]],i);
    }
    //for(int i=1;i<=n;i++) printf("%d\n",st[rt[i]].v);
    dfs(1,0);
    for(int i=1;i<=n;i++) printf("%lld\n",dead[i]);
    for(int i=1;i<=m;i++) printf("%lld\n",deep[begin[i]]-deep[end[i]]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值