洛谷3261 [JLOI2015]城池攻占 (可并堆+左偏树)

一道yy好题。

qwq首先根据题意,不难发现,我们要对于每个点维护一个小根堆,然后每次对于每一个点来说,如果当前的堆顶的骑士的攻击力小于城池的生命值,那就弹出栈。

但是对于修改操作,我们应该怎么做呢?

其实可以直接像线段树那样,类似打标记的方式去做,但是记得要多 p u s h d o w n pushdown pushdown几次来避免一些玄学错误。

nline void pushdown(int x)
{
    if (!x) return;
    if (cheng[x]!=1)
    {
        cheng[ch[x][0]]*=cheng[x];
        cheng[ch[x][1]]*=cheng[x];
        add[ch[x][0]]*=cheng[x];
        add[ch[x][1]]*=cheng[x];
        val[ch[x][0]]*=cheng[x];
        val[ch[x][1]]*=cheng[x];
        cheng[x]=1;
    }
    if (add[x])
    {
        add[ch[x][0]]+=add[x];
        add[ch[x][1]]+=add[x];
        val[ch[x][0]]+=add[x];
        val[ch[x][1]]+=add[x];
        add[x]=0;
    }
}

int merge(int x,int y)
{
    pushdown(x);
    pushdown(y);
    if (x==0 || y==0) return x+y;
    if (val[x]>val[y]) swap(x,y);
    ch[x][1]=merge(ch[x][1],y);
    fa[ch[x][1]]=x;
    if (dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x]=dis[ch[x][1]]+1;
    return x;
}

int pop(int x,int dep)
{
    pushdown(x);
    fa[x]=0;
    val[x]=0;
    endd[x]=dep;
    fa[ch[x][0]]=ch[x][0];
    fa[ch[x][1]]=ch[x][1];
    return merge(ch[x][0],ch[x][1]);
}

那么对于题目要求的每个骑士的初始的城堡,我们可以通过一个 v e c t o r vector vector来合并,对于一个节点来说,先合并好在这个节点开始的那些骑士,然后再去合并他的儿子。

感觉还是有很多细节的(比如说打乘法标记的时候要记得把对应节点的加法标记也乘上对应的值。

直接上代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define rint register int 

using namespace std;

inline ll read()
{
  ll x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 4e5+1e2;
const int maxm = 2*maxn;

int ch[maxn][2];
ll add[maxn],cheng[maxn];
int root[maxn];
int fa[maxn],dis[maxn];
ll h[maxn];
int a[maxn];
ll v[maxn];
ll val[maxn];
int c[maxn];
int deep[maxn];
vector<int> vec[maxn];
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int ans[maxn];
int endd[maxn];

inline void addedge(int x,int y)
{
    nxt[++cnt]=point[x];
    to[cnt]=y;
    point[x]=cnt;
}

int find(int x)
{
    if (fa[x]!=x) return find(fa[x]);
    return fa[x];
}

inline void pushdown(int x)
{
    if (!x) return;
    if (cheng[x]!=1)
    {
        cheng[ch[x][0]]*=cheng[x];
        cheng[ch[x][1]]*=cheng[x];
        add[ch[x][0]]*=cheng[x];
        add[ch[x][1]]*=cheng[x];
        val[ch[x][0]]*=cheng[x];
        val[ch[x][1]]*=cheng[x];
        cheng[x]=1;
    }
    if (add[x])
    {
        add[ch[x][0]]+=add[x];
        add[ch[x][1]]+=add[x];
        val[ch[x][0]]+=add[x];
        val[ch[x][1]]+=add[x];
        add[x]=0;
    }
}

int merge(int x,int y)
{
    pushdown(x);
    pushdown(y);
    if (x==0 || y==0) return x+y;
    if (val[x]>val[y]) swap(x,y);
    ch[x][1]=merge(ch[x][1],y);
    fa[ch[x][1]]=x;
    if (dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x]=dis[ch[x][1]]+1;
    return x;
}

int pop(int x,int dep)
{
    pushdown(x);
    fa[x]=0;
    val[x]=0;
    endd[x]=dep;
    fa[ch[x][0]]=ch[x][0];
    fa[ch[x][1]]=ch[x][1];
    return merge(ch[x][0],ch[x][1]);
}

void solve(int x,int fa,int dep)
{
    deep[x]=dep;
    for (rint i=point[x];i;i=nxt[i])
    {
        int p=to[i];
        if (p==fa) continue;
        solve(p,x,dep+1);
    }
}

void dfs(int x,int fa)
{
    int now = 0;
    for (rint i=0;i<vec[x].size();++i) now = merge(now,vec[x][i]);
    for (rint i=point[x];i;i=nxt[i])
    {
        int p = to[i];
        if (p==fa) continue;
        dfs(p,x);
        now = merge(now,root[p]);
    }
    int num=0;
    while (val[now]<h[x] && now!=0)
    {
        now = pop(now,deep[x]);
        num++;
    }
    root[x]=now;
    ans[x]=num;
    if (a[x]==1)
    {
        cheng[now]*=v[x];
        add[now]*=v[x];
        val[now]*=v[x];
    }
    else
    {
        add[now]+=v[x];
        val[now]+=v[x];
    }
    //cout<<x<<" "<<num<<" "<<root[x]<<" "<<val[now]<<endl;
}

void print(ll x)
{
    if (x>=10) print(x/10);
    putchar(x%10+'0');
}

signed main()
{
  n=read(),m=read();
  for (rint i=1;i<=n;++i) h[i]=read();
  for (rint i=1;i<=m;++i) fa[i]=i,add[i]=0,cheng[i]=1;
  for (rint i=2;i<=n;++i)
  {
  	  int x=read();
      a[i]=read(),v[i]=read();
  	  addedge(x,i);
  	  addedge(i,x);
  }
  for (rint i=1;i<=m;++i)
  {
  	 val[i]=read();
  	 c[i]=read();
  	 vec[c[i]].pb(i);
  }
  solve(1,0,1);
  dfs(1,0);
  for (rint i=1;i<=n;++i)
  {
  	 cout<<ans[i]<<"\n";
  }
  for (rint i=1;i<=m;++i)
  {
  	 cout<<deep[c[i]]-endd[i]<<"\n";
  }
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值