BZOJ4003: [JLOI2015]城池攻佔(洛谷P3261)
阿新 • • 發佈:2018-12-14
左偏樹
用左偏樹維護騎士生命的最小值。從下往上做,每次對一個城池把生命值小的淘汰掉並更新生命。因為權值可以修改所以要有乘和加的標記。乘和加的兩個操作並不會改變當前堆的結構所以可以進行維護。
程式碼:
#include<cctype> #include<cstdio> #include<cstring> #include<algorithm> #define N 300005 #define F inline using namespace std; typedef long long LL; struct tree{ int l,r,d; LL v,f1,f2; }t[N]; struct edge{ int nxt,to; }ed[N]; int n,m,k,h[N],a[N],fa[N],c[N],d[N],rt[N],ans[N],dep[N]; LL df[N],w[N]; F char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); return l==r?EOF:*l++; } F LL _read(){ LL x=0,f=1; char ch=readc(); while (!isdigit(ch)) ch=='-'?f=-1:1,ch=readc(); while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc(); return x*f; } F void mdfy(int x,LL f1,LL f2){ if (!x) return; t[x].v*=f2,t[x].v+=f1; t[x].f1*=f2,t[x].f2*=f2,t[x].f1+=f1; } F void pshd(int x){ mdfy(t[x].l,t[x].f1,t[x].f2),mdfy(t[x].r,t[x].f1,t[x].f2),t[x].f1=0,t[x].f2=1; } int mrg(int x,int y){ if (!x||!y) return x+y; pshd(x),pshd(y); if (t[x].v>t[y].v) swap(x,y); t[x].r=mrg(t[x].r,y); if (t[t[x].l].d<t[t[x].r].d) swap(t[x].l,t[x].r); return t[x].d=t[t[x].r].d+1,x; } void dfs(int x){ dep[x]=dep[fa[x]]+1; for (int i=h[x];i;i=ed[i].nxt) dfs(ed[i].to); for (int i=h[x];i;i=ed[i].nxt) rt[x]=mrg(rt[x],rt[ed[i].to]); while (rt[x]&&t[rt[x]].v<df[x]) pshd(rt[x]),ans[x]++,d[rt[x]]=x,rt[x]=mrg(t[rt[x]].l,t[rt[x]].r); a[x]?mdfy(rt[x],0,w[x]):mdfy(rt[x],w[x],1); } #define add(x,y) ed[++k]=(edge){h[x],y},h[x]=k int main(){ n=_read(),m=_read(); for (int i=1;i<=n;i++) df[i]=_read(); for (int i=2;i<=n;i++) fa[i]=_read(),a[i]=_read(),w[i]=_read(),add(fa[i],i); for (int i=1;i<=m;i++) t[i].v=_read(),c[i]=_read(),t[i].f1=0,t[i].f2=1,rt[c[i]]=mrg(rt[c[i]],i); dfs(1); for (int i=1;i<=n;i++) printf("%d\n",ans[i]); for (int i=1;i<=m;i++) printf("%d\n",dep[c[i]]-dep[d[i]]); return 0; }