传送门: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 ", cnt - 1); 122 else printf("%d ", 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 }