标签:rt int 线段 差分 vol 雨天 lsp rsp sum
1 #include <bits/stdc++.h> 2 #define Re register int 3 #define LL long long 4 #define ki cout << endl; 5 6 using namespace std; 7 8 //打个雨天的尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾尾巴 9 //我复习了lca...............学习了差分.... 10 //可真行 11 /* 12 1 13 2 3 14 4 5 6 7 15 8 9 16 点差分 17 volume_up 18 vol[u]++; 19 vol[v]++; 20 vol[lca(u, v)] --; 21 vol[pre[lca(u, v)]] --; 22 最后求前缀和就是给u - > v路径是都加了个一 23 eg: 1 2 3 4 5 6(普通差分) 24 给 2 - > 5 加一 25 就是 vol[2] + 1 | vol[5] + 1 | vol[6] - 1 26 求前缀和就是2 -> 5都加一,而五之后没加 27 给8 -> 5树上每个点都加一(树上差分) 28 按上边(最上边)操作即可,因为到lca加了两个,而从lca的爹到根都也都多加了2但vol[lca(u, v)]--已经减了一次,所以再减一次就行,而lca留一次,所以只减一个 29 边差分 30 vol[u]++; 31 vol[v]++; 32 vol[lca(u, v)] -= 2; 33 边为点到其父亲的边 34 显而易见lca到跌的边不需要,所以减两个 35 */ 36 namespace kiritokazuto { 37 template <typename T> inline void in(T &x) { 38 int f = 0; x = 0; char c = getchar(); 39 while(c < '0' || c > '9')f |= c == '-', c = getchar(); 40 while(c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); 41 x = f ? -x : x; 42 } 43 template <typename T> inline void ot(T x) { 44 if(x < 0)putchar('-'), x = -x; 45 if(x > 9)ot(x / 10); putchar(x % 10 | '0'); 46 } 47 } 48 /* 49 所以,综上所述,这个题就成了线段树合并的真真正正的板子题 50 但是合并时可能 51 出现vol[rt[x]]不为0 52 但是sum[rt[x]]为0的情况 53 即节点编号为vol[rt[x]]的救济粮数量为0(就是他这里可能是别的改了) 54 所以ans[x] = 0 55 */ 56 using namespace kiritokazuto; 57 const int maxn = 6e6 + 10, Inf = 1e5; 58 int len = 0; 59 int head[maxn]; 60 int tot; 61 int n, m; 62 int ans[maxn]; 63 struct QWMXQ { 64 int next; 65 int to; 66 //int dis; 67 }a[maxn]; 68 int sum[maxn]; 69 int vol[maxn]; 70 int root[maxn]; 71 struct WMX { 72 int lson, rson; 73 #define lsp(x) tr[x].lson 74 #define rsp(x) tr[x].rson 75 #define mid ((l + r) >> 1) 76 }tr[maxn]; 77 //差分直接给每一棵线段树上搞了,所以这里的vol[x]实际上是表示以x为根的子树的答案->从下向上合并的时候 78 inline void Qian(int from, int to) { 79 a[++len].to = to; 80 //a[len].dis = dis; 81 a[len].next = head[from]; 82 head[from] = len; 83 } 84 int f[maxn][20];//老年倍增数组 85 int deep[maxn]; 86 inline void pushup(int rt) { 87 if(lsp(rt) == 0) { 88 sum[rt] = sum[rsp(rt)]; 89 vol[rt] = vol[rsp(rt)]; 90 return; 91 } 92 if(rsp(rt) == 0) { 93 sum[rt] = sum[lsp(rt)]; 94 vol[rt] = vol[lsp(rt)]; 95 return; 96 } 97 if(sum[lsp(rt)] >= sum[rsp(rt)]) { 98 sum[rt] = sum[lsp(rt)]; 99 vol[rt] = vol[lsp(rt)]; 100 //return; 101 }else { 102 sum[rt] = sum[rsp(rt)]; 103 vol[rt] = vol[rsp(rt)]; 104 // return; 105 } 106 } 107 108 inline void insert(int &rt, int l, int r, int pos, int val) { 109 if(!rt)rt = ++tot; 110 if(l == r) { 111 vol[rt] = pos;//存下该节点编号对应的真正树上的编号->动态开点 112 sum[rt] += val; 113 return;//结束啊!!! 114 } 115 if(pos <= mid) insert(lsp(rt), l ,mid, pos, val); 116 else insert(rsp(rt), mid + 1, r, pos, val); 117 pushup(rt); 118 } 119 120 121 inline int merge(int rr, int tt, int l, int r) { 122 if(!rr)return tt; 123 if(!tt)return rr; 124 if(l == r) { 125 sum[rr] += sum[tt]; 126 return rr;//记得返回->叶子 127 } 128 lsp(rr) = merge(lsp(rr), lsp(tt), l, mid); 129 rsp(rr) = merge(rsp(rr), rsp(tt), mid + 1, r); 130 pushup(rr);//记得pushup 131 return rr; 132 } 133 134 void dfs(int x, int fa) { 135 deep[x] = deep[fa] + 1; 136 f[x][0] = fa;//x 的 2 ^ 0 即 x 向上 翻 1的祖先就是他的爹 137 for(Re i = 1; i <= 20; i ++) { 138 f[x][i] = f[f[x][i - 1]][i - 1];//x 的 2 ^ i 的爹是x 的 2 ^ j - 1的 2 ^ j - 1; 139 } 140 for(Re i = head[x], to; i ; i = a[i].next) { 141 to = a[i].to; 142 if(to == fa)continue; 143 dfs(to, x); 144 } 145 } 146 147 int LCA(int a, int b) { 148 if(deep[a] > deep[b])swap(a, b);//a深,把a换上来 149 for(Re i = 20; i >= 0; i --) { 150 if(deep[a] <= deep[f[b][i]])b = f[b][i];//拉到同一层 151 } 152 if(a == b)return a; 153 for(Re i = 20; i >= 0; i --) { 154 if(f[a][i] != f[b][i]) { 155 a = f[a][i]; 156 b = f[b][i]; 157 } 158 } 159 return f[a][0]; 160 } 161 162 inline void work(int x, int fa) { 163 for(Re i = head[x], to; i; i = a[i].next) { 164 to = a[i].to; 165 if(to == fa)continue; 166 work(to, x); 167 root[x] = merge(root[x], root[to], 1, Inf); 168 } 169 ans[x] = vol[root[x]]; 170 if(sum[root[x]] == 0)ans[x] = 0; 171 } 172 signed main () { 173 // freopen("in.txt", "r", stdin); 174 // freopen("out.txt", "w", stdout); 175 in(n); 176 in(m); 177 for(int i = 1, x ,y; i < n; i ++) { 178 in(x); 179 in(y); 180 Qian(x, y); 181 Qian(y, x); 182 } 183 dfs(1, 0); 184 //cout << "?????????"; 185 for(int i = 1, x, y, z; i <= m; i ++) { 186 in(x); 187 in(y); 188 in(z); 189 int lca = LCA(x, y); 190 insert(root[x], 1, Inf, z, 1); 191 insert(root[y], 1, Inf, z, 1); 192 insert(root[lca], 1, Inf, z, -1); 193 insert(root[f[lca][0]], 1, Inf, z, -1); 194 } 195 work(1, 0); 196 for(Re i = 1; i <= n; i ++) { 197 cout << ans[i] << endl; 198 } 199 return 0; 200 }
标签:rt,int,线段,差分,vol,雨天,lsp,rsp,sum 来源: https://www.cnblogs.com/kiritokazuto/p/16120770.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。