BZOJ 4127 Abs 解题报告
这个题感觉很厉害的样子。。
首先我们注意到一点:每次加的 $d$ 都是非负的。
那么就说明一个数只可能从负数变成非负数并且只会变一次。
所以我们就可以暴力地去改变一个数的正负情况。
然后我们就可以用树链剖分,维护一下区间的最大负数和负数的个数就可以了。
时间复杂度 $O(n\log^2 n)$,空间复杂度 $O(n)$。
1 #include <cstdio> 2 typedef long long LL; 3 #define N 262144 + 5 4 #define INF 1234567890987654321LL 5 6 int n, m, tot, cnt, A[N], Head[N], Root[N], Fa[N], Ad[N], Pos[N], Num[N], Dfn[N], Len[N], Size[N], Son[N], q[N]; 7 8 struct Edge 9 { 10 int next, node; 11 }E[N]; 12 13 struct Segment_Tree 14 { 15 int l, r, neg_cnt; 16 LL sum, delta, neg_Max; 17 }h[N]; 18 19 inline void addedge(int u, int v) 20 { 21 E[++ tot].next = Head[u], Head[u] = tot; 22 E[tot].node = v; 23 E[++ tot].next = Head[v], Head[v] = tot; 24 E[tot].node = u; 25 } 26 27 inline LL Abs(LL x) 28 { 29 return x > 0 ? x : -x; 30 } 31 32 inline void dfs(int z) 33 { 34 Size[z] = 1; 35 for (int i = Head[z]; i; i = E[i].next) 36 { 37 int d = E[i].node; 38 if (d == Fa[z]) continue ; 39 Fa[d] = z; 40 dfs(d); 41 Size[z] += Size[d]; 42 } 43 for (int i = Head[z]; i; i = E[i].next) 44 { 45 int d = E[i].node; 46 if (d == Fa[z]) continue ; 47 if (!Son[z] || Size[d] > Size[Son[z]]) 48 Son[z] = d; 49 } 50 } 51 52 inline void update(int x) 53 { 54 h[x].sum = h[h[x].l].sum + h[h[x].r].sum; 55 h[x].neg_Max = h[h[x].l].neg_Max > h[h[x].r].neg_Max ? h[h[x].l].neg_Max : h[h[x].r].neg_Max; 56 h[x].neg_cnt = h[h[x].l].neg_cnt + h[h[x].r].neg_cnt; 57 } 58 59 inline void Build(int &x, int l, int r) 60 { 61 if (!x) x = ++ tot; 62 if (l == r) 63 { 64 h[x].sum = Abs(A[q[l]]); 65 if (A[q[l]] < 0) h[x].neg_Max = A[q[l]], h[x].neg_cnt = 1; 66 else h[x].neg_Max = -INF; 67 return ; 68 } 69 int mid = l + r >> 1; 70 Build(h[x].l, l, mid); 71 Build(h[x].r, mid + 1, r); 72 update(x); 73 } 74 75 inline void apply(int x, int l, int r, LL d) 76 { 77 h[x].sum += d * (r - l + 1 - h[x].neg_cnt * 2); 78 h[x].delta += d; 79 h[x].neg_Max += d; 80 } 81 82 inline void push(int x, int l, int r) 83 { 84 if (h[x].delta) 85 { 86 int mid = l + r >> 1; 87 apply(h[x].l, l, mid, h[x].delta); 88 apply(h[x].r, mid + 1, r, h[x].delta); 89 h[x].delta = 0; 90 } 91 } 92 93 inline void Point_Modify(int x, int l, int r, LL d) 94 { 95 if (l == r) 96 { 97 h[x].sum = -h[x].sum; 98 h[x].neg_Max = -INF; 99 h[x].neg_cnt = 0; 100 return ; 101 } 102 int mid = l + r >> 1; 103 push(x, l, r); 104 if (h[h[x].l].neg_Max > h[h[x].r].neg_Max) 105 Point_Modify(h[x].l, l, mid, d); 106 else Point_Modify(h[x].r, mid + 1, r, d); 107 update(x); 108 } 109 110 inline void Modify(int x, int l, int r, int s, int t, LL d) 111 { 112 if (l == s && r == t) 113 { 114 while (h[x].neg_Max >= -d) 115 Point_Modify(x, l, r, d); 116 apply(x, l, r, d); 117 return ; 118 } 119 push(x, l, r); 120 int mid = l + r >> 1; 121 if (t <= mid) Modify(h[x].l, l, mid, s, t, d); 122 else if (s > mid) Modify(h[x].r, mid + 1, r, s, t, d); 123 else Modify(h[x].l, l, mid, s, mid, d), Modify(h[x].r, mid + 1, r, mid + 1, t, d); 124 update(x); 125 } 126 127 inline LL Query(int x, int l, int r, int s, int t) 128 { 129 if (l == s && r == t) return h[x].sum; 130 push(x, l, r); 131 int mid = l + r >> 1; 132 if (t <= mid) return Query(h[x].l, l, mid, s, t); 133 else if (s > mid) return Query(h[x].r, mid + 1, r, s, t); 134 else return Query(h[x].l, l, mid, s, mid) + Query(h[x].r, mid + 1, r, mid + 1, t); 135 } 136 137 inline void Prepare() 138 { 139 tot = 0; 140 for (int i = 1; i <= n; i ++) 141 { 142 if (Ad[i]) continue ; 143 Dfn[i] = Dfn[Fa[i]] + 1; 144 q[0] = 0; 145 cnt ++; 146 for (int x = i; x; x = Son[x]) 147 { 148 Ad[x] = i, Pos[x] = ++ Len[cnt]; 149 Num[x] = cnt, Dfn[x] = Dfn[i]; 150 q[++ q[0]] = x; 151 } 152 Build(Root[cnt], 1, Len[cnt]); 153 } 154 } 155 156 int main() 157 { 158 #ifndef ONLINE_JUDGE 159 freopen("4127.in", "r", stdin); 160 freopen("4127.out", "w", stdout); 161 #endif 162 163 scanf("%d%d", &n, &m); 164 for (int i = 1; i <= n; i ++) 165 scanf("%d", A + i); 166 for (int i = 1, u, v; i < n; i ++) 167 { 168 scanf("%d%d", &u, &v); 169 addedge(u, v); 170 } 171 dfs(1); 172 Prepare(); 173 for (int op, u, v; m; m --) 174 { 175 scanf("%d", &op); 176 if (op == 1) 177 { 178 LL d; 179 scanf("%d%d%lld", &u, &v, &d); 180 if (Dfn[u] < Dfn[v]) u = u - v, v = u + v, u = v - u; 181 for (; Dfn[u] > Dfn[v]; u = Fa[Ad[u]]) 182 Modify(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u], d); 183 for (; Ad[u] != Ad[v]; u = Fa[Ad[u]], v = Fa[Ad[v]]) 184 { 185 Modify(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u], d); 186 Modify(Root[Num[v]], 1, Len[Num[v]], 1, Pos[v], d); 187 } 188 if (Pos[u] > Pos[v]) u = u - v, v = u + v, u = v - u; 189 Modify(Root[Num[u]], 1, Len[Num[u]], Pos[u], Pos[v], d); 190 } 191 else 192 { 193 scanf("%d%d", &u, &v); 194 LL ans = 0; 195 if (Dfn[u] < Dfn[v]) u = u - v, v = u + v, u = v - u; 196 for (; Dfn[u] > Dfn[v]; u = Fa[Ad[u]]) 197 ans += Query(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u]); 198 for (; Ad[u] != Ad[v]; u = Fa[Ad[u]], v = Fa[Ad[v]]) 199 { 200 ans += Query(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u]); 201 ans += Query(Root[Num[v]], 1, Len[Num[v]], 1, Pos[v]); 202 } 203 if (Pos[u] > Pos[v]) u = u - v, v = u + v, u = v - u; 204 ans += Query(Root[Num[u]], 1, Len[Num[u]], Pos[u], Pos[v]); 205 printf("%lld\n", ans); 206 } 207 } 208 209 #ifndef ONLINE_JUDGE 210 fclose(stdin); 211 fclose(stdout); 212 #endif 213 return 0; 214 }