传送门:嘟嘟嘟
第一反应是树链剖分,但是太长懒得写,然后就想出了一个很不错的做法。
想一下,如果我们改一条边,那么影响的只有他的子树,只要先搞一个dfs序,为什么搞出这个呢?因为有一个性质:一个节点的子树在dfs序上是连续的,所以这道题就变成了一个单点查询,区间修改的线段树(树状数组)板子题。
然后我不到40分钟写完了,非说有的点TLE,debug了一个多点……现在想想,一般遇到这种情况,一定不是什么正经问题。然而当时的我并不这么想,以为线段树太慢了,改成差分+树状数组,各种优化,虽然在luogu卡了过去,然而内网却GG。
终于放弃,到网上找标程,发现写的几乎一模一样,就一行行比对……然后发现我为了省事儿读字母用了cin,按标称改成了scanf……结果最慢的点直接从900多ms变成了200多ms……然后内网秒过了……老子在此立flag:我,mrclr,如果再用cin,我就女装!
心路历程讲完了,发下代码吧
先是线段树的
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cmath> 6 #include<stack> 7 #include<queue> 8 #include<vector> 9 #include<cstdlib> 10 #include<cctype> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 3e5 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) 26 { 27 ans = ans * 10 + ch - '0'; ch = getchar(); 28 } 29 if(last == '-') ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) putchar('-'), x = -x; 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + '0'); 37 } 38 39 int n; 40 vector<int> v[maxn]; 41 42 int dis[maxn], dfsx[maxn], size[maxn], pos[maxn], cnt = 0; 43 void dfs(const int& now) 44 { 45 dfsx[now] = ++cnt; pos[cnt] = now; 46 size[now] = 1; 47 for(int i = 0; i < (int)v[now].size(); ++i) 48 { 49 dis[v[now][i]] = dis[now] + 1; 50 dfs(v[now][i]); 51 size[now] += size[v[now][i]]; 52 } 53 return; 54 } 55 56 int l[maxn << 2], r[maxn << 2], dis2[maxn << 2], lazy[maxn << 2]; 57 void build(const int& L, const int& R, const int& now) 58 { 59 l[now] = L; r[now] = R; 60 if(L == R) {dis2[now] = dis[pos[L]]; return;} 61 int mid = (L + R) >> 1; 62 build(L, mid, now << 1); 63 build(mid + 1, R, now << 1 | 1); 64 dis2[now] = dis2[now << 1] + dis2[now << 1 | 1]; 65 } 66 void pushdown(const int& now) 67 { 68 if(lazy[now]) 69 { 70 lazy[now << 1] += lazy[now]; 71 lazy[now << 1 | 1] += lazy[now]; 72 dis2[now << 1] -= lazy[now]; 73 dis2[now << 1 | 1] -= lazy[now]; 74 lazy[now] = 0; 75 } 76 } 77 void update(const int& L, const int& R, const int& now) 78 { 79 if(!dis2[now]) return; 80 if(l[now] == L && r[now] == R) 81 { 82 dis2[now]--; lazy[now]++; 83 return; 84 } 85 pushdown(now); 86 int mid = (l[now] + r[now]) >> 1; 87 if(R <= mid) update(L, R, now << 1); 88 else if(L > mid) update(L, R, now << 1 | 1); 89 else {update(L, mid, now << 1); update(mid + 1, R, now << 1 | 1);} 90 } 91 int query(const int& id, const int& now) 92 { 93 if(!dis2[now]) return 0; 94 if(l[now] == r[now]) return dis2[now]; 95 pushdown(now); 96 int mid = (l[now] + r[now]) >> 1; 97 if(id <= mid) return query(id, now << 1); 98 else return query(id, now << 1 | 1); 99 } 100 101 int main() 102 { 103 n = read(); 104 for(int i = 1; i < n; ++i) 105 { 106 int x = read(), y = read(); 107 if(y < x) swap(x, y); 108 v[x].push_back(y); 109 } 110 dfs(1); 111 build(1, cnt, 1); 112 int m = read(); 113 char ch[5]; 114 for(int i = 1; i < n + m; ++i) 115 { 116 scanf("%s", ch); 117 if(ch[0] == 'W') 118 { 119 int x = read(); 120 write(query(dfsx[x], 1)); enter; 121 } 122 else 123 { 124 int x = read(), y = read(); 125 if(y > x) swap(x, y); 126 update(dfsx[x], dfsx[x] + size[x] - 1, 1); 127 } 128 } 129 return 0; 130 }
然后又写了个差分+树状数组
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cmath> 6 #include<stack> 7 #include<queue> 8 #include<vector> 9 #include<cstdlib> 10 #include<cctype> 11 using namespace std; 12 #define enter printf("\n") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 3e5 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) 26 { 27 ans = ans * 10 + ch - '0'; ch = getchar(); 28 } 29 if(last == '-') ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) putchar('-'), x = -x; 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + '0'); 37 } 38 39 int n; 40 vector<int> v[maxn]; 41 42 int dis[maxn], dfsx[maxn], size[maxn], pos[maxn], cnt = 0; 43 void dfs(const int& now) 44 { 45 dfsx[now] = ++cnt; pos[cnt] = now; 46 size[now] = 1; 47 if(!v[now].size()) return; 48 for(int i = 0; i < (int)v[now].size(); ++i) 49 { 50 dis[v[now][i]] = dis[now] + 1; 51 dfs(v[now][i]); 52 size[now] += size[v[now][i]]; 53 } 54 } 55 56 int cf[maxn], c[maxn]; 57 inline int lowbit(int x) 58 { 59 return x & -x; 60 } 61 void add(int pos, int x) 62 { 63 while(pos <= cnt) 64 { 65 c[pos] += x; 66 pos += lowbit(pos); 67 } 68 } 69 int sum(int pos) 70 { 71 int ret = 0; 72 while(pos) 73 { 74 ret += c[pos]; 75 pos -= lowbit(pos); 76 } 77 return ret; 78 } 79 80 81 int main() 82 { 83 n = read(); 84 for(int i = 1; i < n; ++i) 85 { 86 int x = read(), y = read(); 87 if(y < x) swap(x, y); 88 v[x].push_back(y); 89 } 90 dfs(1); 91 for(int i = 1; i <= cnt; ++i) cf[i] = dis[pos[i]] - dis[pos[i - 1]]; 92 for(int i = 1; i <= cnt; ++i) add(i, cf[i]); 93 int m = read(); 94 char ch[5]; 95 for(int i = 1; i < n + m; ++i) 96 { 97 scanf("%s", ch); 98 if(ch[0] == 'W') 99 { 100 int x = read(); 101 write(sum(dfsx[x])); enter; 102 } 103 else 104 { 105 int x = read(), y = read(); 106 if(y > x) swap(x, y); 107 add(dfsx[x], -1); add(dfsx[x] + size[x], 1); 108 } 109 } 110 return 0; 111 }
虽然都能过,不过树状数组比线段树快了一倍