[JLOI2015][左偏樹] 城池攻佔
阿新 • • 發佈:2020-08-09
題目連結
考慮每個節點建一個以騎士攻擊力為關鍵字的小根堆,從葉子節點向上掃描,每次彈堆至堆頂騎士攻擊力大於當前城池防禦力,可以採用左偏樹維護,
對於城池的攻擊力改變值,可以借用線段樹區間修改的懶標記思想,打上乘法及加法標記,每次涉及到改變堆結構的操作前下放標記即可。
稍微卡常之後可過
程式碼
# include <iostream> # include <cstdio> # define MAXN 300005 struct edge{ int v, next; }e[MAXN]; int hd[MAXN], cntE; struct heap{ int ls, rs, dis, rt; long long tagA, tagM; // 乘標記,加標記 }hp[MAXN]; struct knight{ long long pow; int fir; }kn[MAXN]; struct city{ int dep; // 深度 long long def; // 防禦力 long long ai, vi; // 改變值 }ct[MAXN]; int death[MAXN], destory[MAXN]; template<typename T> void rd(T & x); void AddE(int u, int v); void DFS(int now, int fa); int Merge(int x, int y); void PushDown(int now); void Calc(int now, long long mul, long long pls); // int Find(int x); int main(){ int n, m; rd<int>(n), rd<int>(m); hp[0].dis = -1; for(int i = 1; i <= n; i++){ rd<long long>(ct[i].def); } for(int i = 2, tmp; i <= n; i++){ rd<int>(tmp), rd<long long>(ct[i].ai), rd<long long>(ct[i].vi); AddE(tmp, i); } for(int i = 1; i <= m; i++){ rd<long long>(kn[i].pow), rd<int>(kn[i].fir); hp[kn[i].fir].rt = Merge(hp[kn[i].fir].rt, i); // 注意每個位置可能不止一個士兵,所以不能直接將 rt 設為 i 而應該合併 hp[i].tagM = 1; } DFS(1, 0); while(hp[1].rt){ PushDown(hp[1].rt); destory[hp[1].rt] = ct[kn[hp[1].rt].fir].dep; hp[1].rt = Merge(hp[hp[1].rt].ls, hp[hp[1].rt].rs); } for(int i = 1; i <= n; i++){ printf("%d\n", death[i]); } for(int i = 1; i <= m; i++){ printf("%d\n", destory[i]); } return 0; } // int Find(int x){ // return hp[x].rt == x ? x : hp[x].rt = Find(hp[x].rt); // } void Calc(int now, long long mul, long long pls){ if(now){ (kn[now].pow *= mul) += pls; hp[now].tagM *= mul; (hp[now].tagA *= mul) += pls; } } void PushDown(int now){ Calc(hp[now].ls, hp[now].tagM, hp[now].tagA); Calc(hp[now].rs, hp[now].tagM, hp[now].tagA); hp[now].tagM = 1, hp[now].tagA = 0; } int Merge(int x, int y){ if(!x || !y){ return x + y; } PushDown(x); PushDown(y); if(kn[x].pow > kn[y].pow){ std::swap(x, y); } hp[x].rs = Merge(hp[x].rs, y); if(hp[hp[x].ls].dis < hp[hp[x].rs].dis){ std::swap(hp[x].ls, hp[x].rs); } hp[x].dis = hp[hp[x].rs].dis + 1; return x; } void DFS(int now, int fa){ ct[now].dep = ct[fa].dep + 1; for(int i = hd[now]; i; i = e[i].next){ DFS(e[i].v, now); hp[now].rt = Merge(hp[now].rt, hp[e[i].v].rt); } while(hp[now].rt && kn[hp[now].rt].pow < ct[now].def){ PushDown(hp[now].rt); death[now] += 1, destory[hp[now].rt] = ct[kn[hp[now].rt].fir].dep - ct[now].dep; hp[now].rt = Merge(hp[hp[now].rt].ls, hp[hp[now].rt].rs); } if(ct[now].ai){ Calc(hp[now].rt, ct[now].vi, 0); } else{ Calc(hp[now].rt, 1, ct[now].vi); } } void AddE(int u, int v){ e[++cntE].v = v, e[cntE].next = hd[u], hd[u] = cntE; } template<typename T> void rd(T & x){ x = 0; T fl = 1; int ch = getchar(); for( ;!isdigit(ch); ch = getchar()){ if(ch == '-'){ fl = -1; } } for( ; isdigit(ch); ch = getchar()){ x = x * 10 + ch - '0'; } x *= fl; }