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 }
4127_Gromah

 

posted @ 2015-06-25 09:36  Gromah  阅读(274)  评论(0编辑  收藏  举报