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

[JLOI2015]城池攻占

stream spa using digi sign sdi swa 第一個 多少

嘟嘟嘟

暴力不難想:一種是以每一個騎士為主,一步步向上爬直到死了;一種是以每一個城池為主,統計哪些騎士在這座城池中死了,然後剩下的騎士再轉移到他的父親節點。

考慮優化:因為城池構成了一個樹形結構,相對於騎士來說結構比較固定。因此我們想辦法優化第二個暴力:每一個節點建一個小根堆,一直彈出堆頂直到堆頂騎士的戰鬥力>=防禦值,然後把剩下的騎士都轉移到他的父親節點取。所以說,父親節點的騎士是由他的子節點的騎士合並而來的。那麽這個堆還要支持合並,左偏樹是一個不錯的選擇。

左偏樹是可以打標記的,因此修改就和線段樹有點像,打一個lazy標記,然後處理到這個節點的時候pushdown就行了。

最後說一下統計答案:每一個城池犧牲多少人好辦,開一計數數組就解決了。關鍵是統計每一個騎士攻占了多少城池。原來我的做法是每攻占了一個城池,就給左偏樹的所有騎士++,實際上有一個更好的辦法:維護樹中每一個節點的深度,則一個騎士攻占的城池數量就是第一個攻占的城池的深度減去死的城池的深度。

技術分享圖片
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 3e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0
; 24 char ch = getchar(), last = ; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - 0; ch = getchar();} 27 if(last == -) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(-); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + 0); 35 } 36 37 int n, m; 38 ll h[maxn], v[maxn]; 39 bool a[maxn]; 40 ll s[maxn]; 41 int c[maxn]; 42 int ans1[maxn], ans2[maxn]; 43 struct Edge 44 { 45 int nxt, to; 46 }e[maxn]; 47 int head[maxn], ecnt = 0; 48 void addEdge(int x, int y) 49 { 50 e[++ecnt] = (Edge){head[x], y}; 51 head[x] = ecnt; 52 } 53 54 int root[maxn], ls[maxn], rs[maxn], dis[maxn], dep[maxn]; 55 ll lzy_mul[maxn], lzy_add[maxn]; 56 void Sign(int now, ll mul, ll add) 57 { 58 if(!now) return; 59 s[now] *= mul; s[now] += add; 60 lzy_mul[now] *= mul; lzy_add[now] *= mul; lzy_add[now] += add; 61 } 62 void pushdown(int now) 63 { 64 Sign(ls[now], lzy_mul[now], lzy_add[now]); 65 Sign(rs[now], lzy_mul[now], lzy_add[now]); 66 lzy_mul[now] = 1; lzy_add[now] = 0; 67 } 68 int merge(int x, int y) 69 { 70 if(!x || !y) return x | y; 71 pushdown(x); pushdown(y); 72 if(s[x] > s[y]) swap(x, y); 73 rs[x] = merge(rs[x], y); 74 if(dis[ls[x]] < dis[rs[x]]) swap(ls[x], rs[x]); 75 dis[x] = dis[rs[x]] + 1; 76 return x; 77 } 78 int Del(int now) 79 { 80 return merge(ls[now], rs[now]); 81 } 82 83 void dfs(int now) 84 { 85 for(int i = head[now]; i; i = e[i].nxt) 86 { 87 dep[e[i].to] = dep[now] + 1; 88 dfs(e[i].to); 89 root[now] = merge(root[now], root[e[i].to]); 90 } 91 while(root[now] && s[root[now]] < h[now]) 92 { 93 pushdown(root[now]); 94 ans1[now]++; 95 ans2[root[now]] = dep[c[root[now]]] - dep[now]; 96 root[now] = Del(root[now]); 97 } 98 if(a[now]) Sign(root[now], v[now], 0); 99 else Sign(root[now], 1, v[now]); 100 } 101 102 int main() 103 { 104 n = read(); m = read(); 105 for(int i = 1; i <= n; ++i) h[i] = read(); 106 for(int i = 2; i <= n; ++i) 107 { 108 int x = read(); a[i] = (bool)read(); v[i] = read(); 109 addEdge(x, i); 110 } 111 for(int i = 1; i <= m; ++i) 112 { 113 s[i] = read(); c[i] = read(); 114 lzy_mul[i] = 1; 115 root[c[i]] = merge(root[c[i]], i); 116 } 117 dep[1] = 1; dfs(1); 118 while(root[1]) 119 { 120 pushdown(root[1]); 121 ans2[root[1]] = dep[c[root[1]]]; 122 root[1] = Del(root[1]); 123 } 124 for(int i = 1; i <= n; ++i) write(ans1[i]), enter; 125 for(int i = 1; i <= m; ++i) write(ans2[i]), enter; 126 return 0; 127 }
View Code

[JLOI2015]城池攻占