1. 程式人生 > >[BZOJ4003][JLOI2015]城池攻占

[BZOJ4003][JLOI2015]城池攻占

左偏樹 problem swa etc ace max https long space

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]城池攻占