zoukankan      html  css  js  c++  java
  • HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4897
    Problem Description
    There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

    The devil likes to make thing in chaos. This kingdom’s road system is like simply a tree(connected graph without cycle). A road has a color of black or white. The devil often wants to make some change of this system.

    In details, we call a path on the tree from a to b consists of vertices lie on the shortest simple path between a and b. And we say an edge is on the path if both its two endpoints is in the path, and an edge is adjacent to the path if exactly one endpoint of it is in the path.

    Sometimes the devil will ask you to reverse every edge’s color on a path or adjacent to a path.

    The king’s daughter, WJMZBMR, is also a cute loli, she is surprised by her father’s lolicon-like behavior. As she is concerned about the road-system’s status, sometimes she will ask you to tell there is how many black edge on a path.

    Initially, every edges is white.
     
    Input
    The first line contains an integer T, denoting the number of the test cases.
    For each test case, the first line contains an integer n, which is the size of the tree. The vertices be indexed from 1.
    On the next n-1 lines, each line contains two integers a,b, denoting there is an edge between a and b. 
    The next line contains an integer Q, denoting the number of the operations.
    On the next Q lines, each line contains three integers t,a,b. t=1 means we reverse every edge’s color on path a to b. t=2 means we reverse every edge’s color adjacent to path a to b. t=3 means we query about the number of black edge on path a to b.

    T<=5.
    n,Q<=10^5.
    Please use scanf,printf instead of cin,cout,because of huge input.
    Output
    For each t=3 operation, output the answer in one line.
     
    题目大意:给一棵树,每条边可以是黑色或者白色,一开始所有边都是白色的。现在有三种操作:①把 a 和 b 之间的简单路径上的所有边的颜色翻转。②把与 a 和 b 之间的简单路径相邻的所有边的颜色翻转。③询问 a 和 b 之间的简单路径上有多少条黑边。
    思路:先贴一段CLJ的官方题解:

       定位:中等题 LCT和树链剖分都可以做,简单起见就说说树链剖分,LCT类似。 

       首先注意到一条路径上是log n条重链和log n条轻边。

       当我们给一个点的所有边上的邻居边打标记时,如果该点在重链上,会影响他的轻孩子们。(要特殊考虑链头和链尾之类的)。

       那么我们可以给重链上的点打标记,表示这个点的轻孩子们被翻转了没。

       那么一个轻边就可以直接询问出来。复杂度:O(n(logn)^2)。

    这个官方题解不怎么详细,我说一下我的解法:

    首先跟普通的树链剖分一样,先给每个结点编上一个编号,每条重链用一个线段树来维护(其实都放到同一个线段树中了,占用不同的位置)

    现在用线段树维护3个值:sum代表这个区间的黑边总数,flip代表这个区间的边是否被翻转颜色,light代表这个区间是否被打上了翻转标记(后面再说这个是啥)

    其中所有边的编号为其靠下方的结点的编号,也就是根的编号在边的维护中没有意义

    其中light代表这个点作为操作②所影响的次数,即它的轻边(不考虑与父节点的边)被翻转次数的奇偶。

    维护这些值,考虑重链上的重边,某条边是黑色当且仅当它在线段树中的flip是1(被翻转了奇数次)。而对于不在重链上的边,它是黑色当且仅当它在线段树中的flip(被翻转的次数奇偶性)和它的父亲被打上翻转标记的次数light的和是奇数(异或值为1)。

    那么,对于操作①,在树链往上走的时候,把所有边都翻转一次即可,没有什么难度。

    对于操作②,在树链往上走的时候,除了要给所有路径上的点打上翻转标记以外,还要:翻转重链上的孩纸边,因为它要翻转而不受翻转标记的影响;翻转重链的父边,它是轻边,会受到重链的父亲的翻转标记的影响,所以直接给翻转一次抵消这种影响。

    对于操作③,在树链往上走的时候,统计重链上的黑边和sum,和不在重链上的黑边(上面有讲)。

    然后这样就差写代码了。

     
    代码(2515MS):
      1 #include <cstdio>
      2 #include <iostream>
      3 #include <algorithm>
      4 #include <cstring>
      5 using namespace std;
      6 typedef long long LL;
      7 
      8 const int MAXV = 100010;
      9 const int MAXE = MAXV << 1;
     10 const int MAXT = MAXV << 2;
     11 
     12 int head[MAXV], ecnt;
     13 int to[MAXE], next[MAXE];
     14 int n, m, T;
     15 //Graph
     16 void initGraph() {
     17     memset(head + 1, -1, n * sizeof(int));
     18     ecnt = 0;
     19 }
     20 
     21 void add_edge(int u, int v) {
     22     to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
     23     to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
     24 }
     25 //Segment Tree
     26 #define ll (x << 1)
     27 #define rr (ll | 1)
     28 #define mid ((l + r) >> 1)
     29 int sum[MAXT], flip[MAXT];
     30 int light[MAXT];//轻边是否翻转
     31 
     32 void initSegmentTree() {
     33     memset(sum + 1, 0, 4 * n * sizeof(int));
     34     memset(flip + 1, 0, 4 * n * sizeof(int));
     35     memset(light + 1, 0, 4 * n * sizeof(int));
     36 }
     37 
     38 void pushdown(int x, int l, int r) {
     39     if(flip[x]) {
     40         flip[ll] ^= 1;
     41         sum[ll] = (mid - l + 1) - sum[ll];
     42         flip[rr] ^= 1;
     43         sum[rr] = (r - mid) - sum[rr];
     44         flip[x] = 0;
     45     }
     46     if(light[x]) {
     47         light[ll] ^= 1;
     48         light[rr] ^= 1;
     49         light[x] = 0;
     50     }
     51 }
     52 
     53 void maintain(int x) {
     54     sum[x] = sum[ll] + sum[rr];
     55 }
     56 
     57 void modifyFlip(int x, int l, int r, int a, int b) {
     58     if(a <= l && r <= b) {
     59         flip[x] ^= 1;
     60         sum[x] = (r - l + 1) - sum[x];
     61     } else {
     62         pushdown(x, l, r);
     63         if(a <= mid) modifyFlip(ll, l, mid, a, b);
     64         if(mid < b) modifyFlip(rr, mid + 1, r, a, b);
     65         maintain(x);
     66     }
     67 }
     68 
     69 void modifyLight(int x, int l, int r, int a, int b) {
     70     if(a <= l && r <= b) {
     71         light[x] ^= 1;
     72     } else {
     73         pushdown(x, l, r);
     74         if(a <= mid) modifyLight(ll, l, mid, a, b);
     75         if(mid < b) modifyLight(rr, mid + 1, r, a, b);
     76     }
     77 }
     78 
     79 int queryFlip(int x, int l, int r, int a, int b) {
     80     if(a <= l && r <= b) {
     81         return sum[x];
     82     } else {
     83         int res = 0;
     84         pushdown(x, l, r);
     85         if(a <= mid) res += queryFlip(ll, l, mid, a, b);
     86         if(mid < b) res += queryFlip(rr, mid + 1, r, a, b);
     87         return res;
     88     }
     89 }
     90 
     91 int queryLight(int x, int l, int r, int a, int b) {
     92     if(a <= l && r <= b) {
     93         return light[x];
     94     } else {
     95         int res = 0;
     96         pushdown(x, l, r);
     97         if(a <= mid) res += queryLight(ll, l, mid, a, b);
     98         if(mid < b) res += queryLight(rr, mid + 1, r, a, b);
     99         return res;
    100     }
    101 }
    102 //树链剖分
    103 int fa[MAXV], size[MAXV], son[MAXV], top[MAXV], tid[MAXV], dep[MAXV];
    104 int dfs_clock;
    105 
    106 void dfs_size(int u, int f, int depth) {
    107     fa[u] = f; dep[u] = depth;
    108     size[u] = 1; son[u] = 0;
    109     int maxsize = 0;
    110     for(int p = head[u]; ~p; p = next[p]) {
    111         int &v = to[p];
    112         if(v == f) continue;
    113         dfs_size(v, u, depth + 1);
    114         size[u] += size[v];
    115         if(size[v] > maxsize) {
    116             son[u] = v;
    117             maxsize = size[v];
    118         }
    119     }
    120 }
    121 
    122 void dfs_heavy_edge(int u, int ancestor) {
    123     tid[u] = ++dfs_clock; top[u] = ancestor;
    124     if(son[u]) dfs_heavy_edge(son[u], ancestor);
    125     for(int p = head[u]; ~p; p = next[p]) {
    126         int &v = to[p];
    127         if(v == fa[u] || v == son[u]) continue;
    128         dfs_heavy_edge(v, v);
    129     }
    130 }
    131 
    132 void modifyFlip(int a, int b) {
    133     while(top[a] != top[b]) {
    134         if(dep[top[a]] < dep[top[b]]) swap(a, b);
    135         modifyFlip(1, 1, n, tid[top[a]], tid[a]);
    136         a = fa[top[a]];
    137     }
    138     if(a != b) {
    139         if(dep[a] < dep[b]) swap(a, b);
    140         modifyFlip(1, 1, n, tid[son[b]], tid[a]);
    141     }
    142 }
    143 
    144 void modifyLight(int a, int b) {
    145     while(top[a] != top[b]) {
    146         if(dep[top[a]] < dep[top[b]]) swap(a, b);
    147         modifyLight(1, 1, n, tid[top[a]], tid[a]);
    148         if(son[a]) modifyFlip(1, 1, n, tid[son[a]], tid[son[a]]);
    149         modifyFlip(1, 1, n, tid[top[a]], tid[top[a]]);
    150         a = fa[top[a]];
    151     }
    152     if(dep[a] < dep[b]) swap(a, b);
    153     modifyLight(1, 1, n, tid[b], tid[a]);
    154     if(fa[b]) modifyFlip(1, 1, n, tid[b], tid[b]);
    155     if(son[a]) modifyFlip(1, 1, n, tid[son[a]], tid[son[a]]);
    156 }
    157 
    158 int query(int a, int b) {
    159     int res = 0;
    160     while(top[a] != top[b]) {
    161         if(dep[top[a]] < dep[top[b]]) swap(a, b);
    162         if(a != top[a]) res += queryFlip(1, 1, n, tid[son[top[a]]], tid[a]);
    163         res += queryFlip(1, 1, n, tid[top[a]], tid[top[a]]) ^ queryLight(1, 1, n, tid[fa[top[a]]], tid[fa[top[a]]]);
    164         a = fa[top[a]];
    165     }
    166     if(a != b) {
    167         if(dep[a] < dep[b]) swap(a, b);
    168         res += queryFlip(1, 1, n, tid[son[b]], tid[a]);
    169     }
    170     return res;
    171 }
    172 
    173 void ask() {
    174     int a, b;
    175     while(cin>>a>>b && a + b) {
    176         cout<<query(a, b)<<endl;
    177     }
    178 }
    179 
    180 int main() {
    181     scanf("%d", &T);
    182     while(T--) {
    183         scanf("%d", &n);
    184         initGraph();
    185         for(int i = 1, a, b; i < n; ++i) {
    186             scanf("%d%d", &a, &b);
    187             add_edge(a, b);
    188         }
    189         initSegmentTree();
    190         dfs_clock = 0;
    191         dfs_size(1, 0, 0);
    192         dfs_heavy_edge(1, 1);
    193         scanf("%d", &m);
    194         for(int i = 0, op, a, b; i < m; ++i) {
    195             scanf("%d%d%d", &op, &a, &b);
    196             if(op == 1) modifyFlip(a, b);
    197             if(op == 2) modifyLight(a, b);
    198             if(op == 3) printf("%d
    ", query(a, b));
    199             //if(i == 1) ask();
    200         }
    201     }
    202 }
    View Code
  • 相关阅读:
    (转) Nova是如何统计OpenStack资源
    (转) 一次批量重启引发的Neutron网络故障
    (转)理解Keystone的四种Token
    neutron 虚拟机网络问题调试
    转 Nova: 虚机的块设备总结 [Nova Instance Block Device]
    kvm 客户机系统的代码是如何运行的
    12 while循环
    11猜拳游戏
    10 if 嵌套
    09 if...elif..else语句
  • 原文地址:https://www.cnblogs.com/oyking/p/3887058.html
Copyright © 2011-2022 走看看