传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1095

首先我必须得感谢yzjc的细心讲解和某岛的题解,如果没有的话我相信我现在还在纠结。。不过某岛的上面写的后面我没有看懂,然后yzjc就给我讲了一个可看的合并。不过由于我自己写的比较的丑,在bzoj的跑的还是比较的慢。。。

首先这道题需要转成一个括号序列,然后我们可以发现两个点之间的路径可以通过某种加法得到,假设向下走为+1, 向上走是 -1,并且我们在这个序列中加入原来的点,也就是一个点在序列中会有三个点表示,这个时候发现两点之间的距离是可以分为两段——一段向上的-1的然后一段+1的(一段中出现的可匹配的括号已经合并了),答案就是前段的-1的和的相反数,加上后面的+1的和。 而如果要使值最大,在不考虑点颜色的情况下,那么这个分割点的应该是lca,不过这个不重要,因为需要找到的是一个值最大,lca具体事哪个位置并不重要

那么考虑答案合并的时候,对于一个答案,那么他可以被lson的答案和rson的答案更新,同时还有可能有中间的一段。而中间一段的分割点可能在中间点的左边或者右边。在左边的时候那么就是左边的后缀的最大的答案加上右边最大的前缀和(相当于右边一定是向下的一段) 在右边的时候就是左边后缀最小和的绝对值+右边前缀答案最大值。然后前缀后缀和参照最大字段和,然后最大答案前缀和后缀类似,前缀的话是左边的前缀,左边的全局答案(新的量)+右边的前缀最大和,左边的和的相反数家右边的前缀最大答案。而刚刚提到的全局答案指的是从区间左边到区间右边整个的答案类似全局的和。 而这个更新方式相当于是找个最大值(因为找lca相当于找一个最大值), 参考一下前面的答案合并就好了

不知道说了这么多好像有点乱= = 不过确实他就是这么的乱。 然后考虑颜色,黑点0,白点INF表示不可取,边的前缀答案和后缀答案及其相关量也是INF,因为边不能单独存在而是要必须要黑点最为端点

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 const int maxn = 100010;
  8 const int INF = 0x3f3f3f3f;
  9 
 10 struct node {
 11     int data, ans, sum, lsum, rsum, lans, rans;
 12     node *l ,*r;
 13 }tr[maxn * 10]; int trne = 0;
 14 node* root; 
 15 
 16 void test(node* x, int l, int r) {
 17     cout << l <<" "<< r <<" "<< x-> data <<" " << x-> ans <<" "<< x-> sum <<" "<< x-> lsum <<" "<< x-> rsum <<" "<<x-> lans <<" "<< x-> rans <<" "<< endl;
 18     if(l ^ r) {
 19         int mid = (l + r) >> 1;
 20         test(x-> l, l, mid), test(x-> r, mid + 1, r);
 21     }
 22 }
 23 
 24 node* build(int l, int r) {
 25     node* now = tr + trne ++;
 26     if(l ^ r) {
 27         int mid = (l + r) >> 1;
 28         now-> l = build(l, mid);
 29         now-> r = build(mid + 1, r);
 30     }
 31     return now;
 32 }
 33 
 34 void update(node *x) {
 35     if(x-> l) {
 36         x-> data = max(max(x-> l-> data, x-> r-> data), max(x-> l-> rans + x-> r-> lsum, -x-> l-> rsum + x-> r-> lans));
 37         x-> ans = max(x-> l-> ans + x-> r-> sum, -x-> l-> sum + x-> r-> ans); 
 38         x-> sum = x-> l-> sum + x-> r-> sum;
 39         x-> lsum = max(x-> l-> lsum, x-> l-> sum + x-> r-> lsum);
 40         x-> rsum = min(x-> r-> rsum, x-> r-> sum + x-> l-> rsum);
 41         x-> lans = max((x-> l-> lans), max(x-> l-> ans + x-> r-> lsum, -x-> l-> sum + x-> r-> lans));
 42         x-> rans = max((x-> r-> rans), max(x-> l-> rans + x-> r-> sum, -x-> l-> rsum + x-> r-> ans));
 43     }
 44 }  
 45 
 46 void insert(node* x, int l, int r, int v, int pos, int col) {
 47     if(l == r) {
 48         x-> ans = x-> data = x-> sum = x-> lsum = x-> rsum = x-> lans = x-> rans = 0;
 49         x-> data = -INF;
 50         if(!v) {
 51             if(col == 0) x-> lsum = -INF, x-> rsum = INF, x-> lans = -INF, x-> rans = -INF, x-> ans = -INF, x-> data = -INF; 
 52         }
 53         else {
 54             x-> sum = v; x-> ans = abs(v); x-> data = abs(v);
 55             if(v > 0) x-> lsum = -INF, x-> rsum = INF,  x-> lans = x-> rans = -INF, x-> data = -INF, x-> ans = 1;
 56             else x-> rsum = INF, x-> lsum = -INF, x-> lans = x-> rans = -INF, x-> data = -INF, x-> ans = 1; 
 57         }
 58     }
 59     else {
 60         int mid = (l + r) >> 1;
 61         if(pos <= mid) insert(x-> l, l, mid, v, pos, col);
 62         else insert(x-> r, mid + 1, r, v, pos, col);
 63         update(x);
 64     }
 65 }
 66 
 67 struct edge {
 68     int t; edge* next; 
 69 }e[maxn * 2], *head[maxn]; int ne = 0;
 70 
 71 void addedge(int f, int t) {
 72     e[ne].t = t, e[ne].next = head[f], head[f] = e + ne ++;
 73 }
 74 
 75 int in[maxn], map[maxn], out[maxn], c[maxn], num = 0, n, m;
 76 int cnt = 0;
 77 
 78 void dfs(int x, int fa) {
 79     in[x] = num ++, map[x] = num ++; 
 80     for(edge* p = head[x]; p; p = p-> next) {
 81         if(p-> t != fa) dfs(p-> t, x);
 82     }
 83     out[x] = num ++;
 84 }
 85 
 86 int int_get() {
 87     int x = 0; char c = (char)getchar();
 88     while(!isdigit(c) && c != '-') c = (char)getchar(); 
 89     bool f = 0; 
 90     if(c == '-') c = (char)getchar(), f = 1;
 91     while(isdigit(c)) {
 92         x = x * 10 + (int)(c - '0'); 
 93         c = (char)getchar();
 94     }
 95     if(f) x = -x;
 96     return x;
 97 }
 98 
 99 void read() {
100     n = int_get(); cnt = n;
101     for(int i = 1; i < n; ++ i) {
102         int u, v; u = int_get(), v = int_get(); 
103         addedge(u, v), addedge(v, u); 
104     }
105     for(int i = 1; i <= n; ++ i) c[i] = 1;
106     dfs(1, 0); num -= 2; root = build(1, num); 
107     for(int i = 1; i <= n; ++ i) {
108         insert(root, 1, num, 0, map[i], c[i]);
109         if(i != 1) {
110             insert(root, 1, num, 1, in[i], 0);
111             insert(root, 1, num, -1, out[i], 0);
112         }
113     }
114 }
115 
116 void sov() {
117     m = int_get(); 
118     while(m --) {
119         char s[10]; scanf("%s", s + 1);
120         if(s[1] == 'G') {
121             if(cnt <= 1) printf("%d\n", cnt - 1);
122             else printf("%d\n", root-> data);
123         }
124         if(s[1] == 'C') {
125             int x = int_get(); 
126             if(c[x]) cnt --;
127             else cnt ++;
128             c[x] = !c[x];
129             insert(root, 1, num, 1, in[x], 0);
130             insert(root, 1, num, 0, map[x], c[x]); 
131             insert(root, 1, num, -1, out[x], 0);
132         }
133     }
134     //test(root, 1, num); cout << endl;
135 }
136 
137 int main() {
138     freopen("test.in", "r", stdin);
139     freopen("test.out", "w", stdout);
140     read(); sov();
141     //update(root-> r);
142     return 0;
143 }
View Code