[POI2007]MEG-Megalopolis

传送门:嘟嘟嘟

 

第一反应是树链剖分,但是太长懒得写,然后就想出了一个很不错的做法。

想一下,如果我们改一条边,那么影响的只有他的子树,只要先搞一个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 }
View Code

然后又写了个差分+树状数组

  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("
")
 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 }
View Code

虽然都能过,不过树状数组比线段树快了一倍

原文地址:https://www.cnblogs.com/mrclr/p/9485885.html