• SPOJ 16549


    题意

    有操作

    $0$ $u$:询问有多少个节点 $v$ 满足路径 $u$ 到 $v$ 上所有节点(包括)都拥有相同的颜色
    $1$ $u$:翻转 $u$ 的颜色

    题解

    直接用一个 $LCT$ 去暴力删边连边显然会 $T$

    那么只有两个颜色的话就可以建两棵 $LCT$ ,观察到每次单点修改颜色时其子树所包含连通块在原颜色树上与其父亲所代表连通块断开,所以可以看作断开与父节点的边(实际上是点化边的思想),那么其它常规操作即可

    注意要建个虚拟节点作为根节点的父亲

    注意 $0$ 操作询问的输出,详细解释有在代码注释中给出

    代码

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 using namespace std;
      6 
      7 const int MAXN = 1e06 + 10;
      8 const int MAXM = 1e06 + 10;
      9 
     10 struct LinkedForwardStar {
     11     int to;
     12 
     13     int next;
     14 } ;
     15 
     16 LinkedForwardStar Link[MAXM << 1];
     17 int Head[MAXN]= {0};
     18 int size = 0;
     19 
     20 void Insert (int u, int v) {
     21     Link[++ size].to = v;
     22     Link[size].next = Head[u];
     23 
     24     Head[u] = size;
     25 }
     26 
     27 int N, M;
     28 int ances[MAXN];
     29 
     30 struct Link_Cut_Tree {
     31     int father[MAXN];
     32     int son[MAXN][2];
     33     int subtree[MAXN], virsize[MAXN];
     34 
     35     void init () {
     36         for (int i = 1; i <= N; i ++)
     37             father[i] = son[i][0] = son[i][1] = subtree[i] = virsize[i] = 0;
     38     }
     39     int isroot (int p) {
     40         return son[father[p]][0] != p && son[father[p]][1] != p;
     41     }
     42     int sonbel (int p) {
     43         return son[father[p]][1] == p;
     44     }
     45     void pushup (int p) {
     46         subtree[p] = subtree[son[p][0]] + subtree[son[p][1]] + virsize[p] + 1;
     47     }
     48     void rotate (int p) {
     49         int fa = father[p], anc = father[fa];
     50         int s = sonbel (p);
     51         son[fa][s] = son[p][s ^ 1];
     52         if (son[fa][s])
     53             father[son[fa][s]] = fa;
     54         if (! isroot (fa))
     55             son[anc][sonbel (fa)] = p;
     56         father[p] = anc;
     57         son[p][s ^ 1] = fa, father[fa] = p;
     58         pushup (fa), pushup (p);
     59     }
     60     void splay (int p) {
     61         for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
     62             if (! isroot (fa))
     63                 sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
     64     }
     65     void Access (int p) {
     66         for (int tp = 0; p; tp = p, p = father[p]) {
     67             splay (p);
     68             virsize[p] += subtree[son[p][1]];
     69             son[p][1] = tp;
     70             virsize[p] -= subtree[son[p][1]];
     71             pushup (p);
     72         }
     73     }
     74     int findroot (int p) {
     75         Access (p), splay (p);
     76         while (son[p][0])
     77             p = son[p][0];
     78         splay (p);
     79         return p;
     80     }
     81     void link (int p) {
     82         int fa = ances[p];
     83         splay (p);
     84         father[p] = fa;
     85         Access (fa), splay (fa);
     86         subtree[fa] += subtree[p], virsize[fa] += subtree[p];
     87     }
     88     void cut (int p) {
     89         Access (p), splay (p);
     90         father[son[p][0]] = 0, son[p][0] = 0;
     91         pushup (p);
     92     }
     93 } ;
     94 Link_Cut_Tree LCT[2];
     95 
     96 void DFS (int root, int father) {
     97     ances[root] = father;
     98     LCT[0].link (root);
     99     for (int i = Head[root]; i; i = Link[i].next) {
    100         int v = Link[i].to;
    101         if (v == father)
    102             continue;
    103         DFS (v, root);
    104     }
    105 }
    106 
    107 int Colour[MAXN]= {0};
    108 
    109 int getnum () {
    110     int num = 0;
    111     char ch = getchar ();
    112 
    113     while (! isdigit (ch))
    114         ch = getchar ();
    115     while (isdigit (ch))
    116         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
    117 
    118     return num;
    119 }
    120 
    121 int main () {
    122     N = getnum ();
    123     for (int i = 1; i <= N; i ++)
    124         LCT[0].subtree[i] = LCT[1].subtree[i] = 1;
    125     for (int i = 1; i < N; i ++) {
    126         int u = getnum (), v = getnum ();
    127         Insert (u, v), Insert (v, u);
    128     }
    129     DFS (1, N + 1);
    130     M = getnum ();
    131     for (int Case = 1; Case <= M; Case ++) {
    132         int opt = getnum (), p = getnum ();
    133         int col = Colour[p];
    134         if (opt == 0) {
    135             int anc = LCT[col].findroot (p);
    136             printf ("%d
    ", LCT[col].subtree[LCT[col].son[anc][1]]);
    137             // 注意,因为有可能存在两个不连通的连通快在LCT上连通,又在Access后右节点仅包含当前链
    138             // 故需输出右子树信息而并非减一,否则有可能会算上另一个连通块的答案
    139         }
    140         else if (opt == 1)
    141             LCT[col].cut (p), LCT[Colour[p] ^= 1].link (p);
    142     }
    143 
    144     return 0;
    145 }
    146 
    147 /*
    148 5
    149 1 2
    150 1 3
    151 1 4
    152 1 5
    153 3
    154 0 1
    155 1 1
    156 0 1
    157 */
    158 
    159 /*
    160 5
    161 1 2
    162 2 3
    163 3 4
    164 4 5
    165 3
    166 1 1
    167 1 3
    168 0 1
    169 */
  • 相关阅读:
    skynet源代码学习
    白话经典算法系列之七 堆与堆排序
    数据结构与算法二
    [hadoop系列]Pig的安装和简单演示样例
    感动前行——给医学媳妇写的演讲稿(非IT类)
    怎样提高团队管理能力3
    Linux守护进程的编程实现
    人脸识别 开放书籍 下载地址
    Objective-C中经常使用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect
    动态规划整理(两)
  • 原文地址:https://www.cnblogs.com/Colythme/p/10218051.html
Copyright © 2020-2023  润新知