题意:给定点数n<=300000的一棵树,然后初始时每条边权值为1,接下来按照时间点先后顺序的n+m-1个操作,

        操作有两种:

             1.A a b 把a到b的边权改为0

             2.W u 求1号点到u号点的路径权值和

思路:如果现在把题目简化为是在一条直线上的操作,每次在中间删除相邻边权值或者查询某个点到1号点的权值和

        我们很容易想把询问离线,然后从1->n扫描1遍,然后用一个树状数组维护前缀和即可。。

        到了本题利用dfs序显然就可以转化成线性模型,

       具体的话

       做到点u,

        如果有一个操作1在(u, fa[u])的边,时间为t,那么在t时间点删除一个点

        如果有一个操作2在u点,时间为t,那么就等价于查询1~u路径上的点数-t时间内删除的点数

        回溯时把操作还原

code(stl):

  1 #pragma comment(linker, "/STACK:102400000,102400000")  
  2 #include<cstdio>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<cmath>
  7 #include<algorithm>
  8 #include<string>
  9 #include<map>
 10 #include<set>
 11 #include<vector>
 12 #include<queue>
 13 #include<stack>
 14 #include<ctime>
 15 #define x first
 16 #define y second
 17 #define M0(x)  memset(x, 0, sizeof(x))
 18 #define vii vector<int>::iterator
 19 #define vpi vector<pair<int, int> >::iterator
 20 #define Inf  0x7fffffff
 21 using namespace std;
 22 typedef pair<int, int> pii;
 23 const int maxn = 300002;
 24 vector<int> e[maxn];
 25 vector<pii> q[maxn];
 26 int n, m, ans[maxn<<1];
 27 int pos[maxn<<1];
 28 
 29 inline void R(int &ret){
 30     ret = 0;
 31     bool ok = 0;
 32     for( ; ;){
 33         int c = getchar();
 34         if (c >= '0' && c <= '9') ret = (ret << 3) + (ret << 1) + c - '0', ok = 1;
 35         else if (ok) return;
 36     }
 37 }
 38 
 39 
 40 void init(){
 41      int u, v;
 42     // for (int i = 1; i <= n; ++i) e[i].clear(), q[i].clear();
 43      pii tmp;
 44      for (int i = 1; i < n; ++i)
 45           R(u), R(v), e[u].push_back(v), e[v].push_back(u);
 46      char op[10];
 47      R(m);
 48      int nm = n + m - 1;
 49      int n1 = 1;
 50      for (int i = 1; i <= nm; ++i){
 51            scanf("%s", op);
 52            if (op[0] == 'A') ++n1; 
 53            tmp.x = i;
 54            pos[i] = n1;
 55            if (op[0] == 'W')
 56                   R(u), tmp.y = -1, q[u].push_back(tmp);
 57            else {
 58                   R(u), R(v);
 59                   tmp.y = v, q[u].push_back(tmp);
 60                   tmp.y = u, q[v].push_back(tmp);
 61            }
 62      }
 63 //     cout << n1 << endl;
 64 }
 65 
 66 int vis[maxn], s[maxn], dep[maxn];
 67 void update(int x,const int& v){
 68      for (; x<=n; x += x&(-x)) s[x] += v;
 69 }
 70 
 71 int query(int x){
 72     int res = 0;
 73     for (; x>0; x -= x&(-x)) res += s[x];
 74     return  res;
 75 }
 76 
 77 int ss;
 78 void  dfs(const int& u){
 79       vis[u] = 1;
 80       for (vpi it = q[u].begin(); it != q[u].end(); ++it) 
 81           if (it->y != -1 && vis[it->y])  update(pos[it->x], 1);
 82       for (vpi it = q[u].begin(); it != q[u].end(); ++it) 
 83           if (it->y == -1)  ans[it->x] = dep[u] - query(pos[it->x]);
 84       for (vii it = e[u].begin(); it != e[u].end(); ++it) 
 85           if (!vis[*it])  dep[*it] = dep[u] + 1, dfs(*it);
 86       for (vpi it = q[u].begin(); it != q[u].end(); ++it) 
 87           if (it->y != -1 && dep[it->y] < dep[u])  update(pos[it->x], -1);
 88 }
 89 
 90 void solve(){
 91      memset(ans, -1, sizeof(int) * (n+m+10));
 92      memset(vis, 0, sizeof(int) * (n+10));
 93      memset(s, 0, sizeof(int) * (n+10));
 94      dep[1] = 0;
 95      dfs(1);
 96      int nm = n + m;
 97      for (int i = 1; i < nm; ++i) 
 98           if (ans[i] >= 0) printf("%d\n", ans[i]); 
 99 }
100 
101 int main(){
102     while (scanf("%d", &n) != EOF){
103           init();
104           solve();
105     }
106     return 0;
107 }
View Code

相关文章: