Luogu P3261 [JLOI2015]城池攻占

dfs时,用可并的小根堆去维护所有活下来的骑士;更新时就直接往外弹即可;然后堆上要维护乘法和加法标记。

#include<iostream>
#include<cstdio>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline ll g() { register ll x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=300010;
int n,m; bool flg[N];
int ls[N],rs[N],d[N],ans1[N],ans2[N];
int vr[N],nxt[N],fir[N],cnt,dep[N],rt[N],st[N];
inline void add(int u,int v) 
  {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
ll ad[N],ml[N],h[N],vl[N],tg[N];
inline void cal(int x,ll M,ll A) {
  vl[x]=vl[x]*M+A;
  ad[x]=ad[x]*M+A,ml[x]*=M;
}
inline void spread(int x) {
  if(!ad[x]&&ml[x]==1) return ;
  if(ls[x]) cal(ls[x],ml[x],ad[x]);
  if(rs[x]) cal(rs[x],ml[x],ad[x]);
  ml[x]=1,ad[x]=0;
}
inline int merge(int x,int y) {
  if(!x||!y) return x+y;
  spread(x),spread(y);
  if(vl[x]>vl[y]) swap(x,y);
  rs[x]=merge(rs[x],y);
  if(d[ls[x]]<d[rs[x]]) swap(ls[x],rs[x]);
  d[x]=d[rs[x]]+1; return x;
}
inline void dfs(int u) {
  for(R i=fir[u];i;i=nxt[i]) {
    R v=vr[i];
    dep[v]=dep[u]+1,dfs(v),rt[u]=merge(rt[u],rt[v]);
  }
  while(rt[u]&&vl[rt[u]]<h[u]) {
    spread(rt[u]);
    ++ans1[u];ans2[rt[u]]=dep[st[rt[u]]]-dep[u];
    rt[u]=merge(ls[rt[u]],rs[rt[u]]);
  } 
  if(flg[u]) cal(rt[u],tg[u],0);
  else cal(rt[u],1,tg[u]); 
}
inline void main() {
  n=g(),m=g();
  for(R i=1;i<=n;++i) h[i]=g();
  for(R i=2,f;i<=n;++i) 
    f=g(),flg[i]=g(),tg[i]=g(),add(f,i);
  for(R i=1;i<=m;++i) 
    vl[i]=g(),st[i]=g(),
    rt[st[i]]=merge(rt[st[i]],i);
  dfs(1);
  while(rt[1]) 
    spread(rt[1]),
    ans2[rt[1]]=dep[st[rt[1]]]+1,
    rt[1]=merge(ls[rt[1]],rs[rt[1]]);
  for(R i=1;i<=n;++i) printf("%d
",ans1[i]);
  for(R i=1;i<=m;++i) printf("%d
",ans2[i]);
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.19

原文地址:https://www.cnblogs.com/Jackpei/p/12215025.html