[JLOI2015]城池攻占
Posted mrclr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JLOI2015]城池攻占相关的知识,希望对你有一定的参考价值。
暴力不难想:一种是以每一个骑士为主,一步步向上爬直到死了;一种是以每一个城池为主,统计哪些骑士在这座城池中死了,然后剩下的骑士再转移到他的父亲节点。
考虑优化:因为城池构成了一个树形结构,相对于骑士来说结构比较固定。因此我们想办法优化第二个暴力:每一个节点建一个小根堆,一直弹出堆顶直到堆顶骑士的战斗力>=防御值,然后把剩下的骑士都转移到他的父亲节点取。所以说,父亲节点的骑士是由他的子节点的骑士合并而来的。那么这个堆还要支持合并,左偏树是一个不错的选择。
左偏树是可以打标记的,因此修改就和线段树有点像,打一个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 }
以上是关于[JLOI2015]城池攻占的主要内容,如果未能解决你的问题,请参考以下文章