zoukankan      html  css  js  c++  java
  • BZOJ3674 可持久化并查集加强版

    这是以前做的一道题。

    并查集 <=>一个father数组,于是可持久化并查集 <=>可持久化数组。

    然后数组如何可持久化呢?用可持久化线段树实现。

    每次合并就等价于修改father数组的一个值,就是线段树点修改。

    然后查询也是,查father数组中的一个值,就是线段树点查询。

    要查询历史版本,就套上可持久化即可。

     1 /**************************************************************
     2     Problem: 3674
     3     User: rausen
     4     Language: C++
     5     Result: Accepted
     6     Time:1496 ms
     7     Memory:158228 kb
     8 ****************************************************************/
     9  
    10 #include <cstdlib> 
    11 #include <cstdio>
    12 #include <algorithm>
    13  
    14 using namespace std;
    15  
    16 struct segment{
    17     int ls, rs, v, dep;
    18 } seg[10000000];
    19 int tot, last, m, n, root[300000];
    20  
    21 void build_seg(int &p, int l, int r){
    22     if (!p) p = ++tot;
    23     if (l == r){
    24         seg[p].v = l;
    25         return;
    26     }
    27     int m = (l + r) >> 1;
    28     build_seg(seg[p].ls, l, m);
    29     build_seg(seg[p].rs, m + 1, r);
    30 }
    31  
    32 void modify(int l, int r, int x, int &y, int pos, int val){
    33     y = ++tot;
    34     if (l == r){
    35         seg[y].v = val;
    36         return;
    37     }
    38     seg[y].ls = seg[x].ls;
    39     seg[y].rs = seg[x].rs;
    40     int m = (l + r) >> 1;
    41     if (pos <= m) modify(l, m, seg[x].ls, seg[y].ls, pos, val);
    42     else modify(m + 1, r, seg[x].rs, seg[y].rs, pos, val);
    43 }
    44  
    45 void add(int p, int l, int r, int pos){
    46     if (l == r){
    47         ++seg[p].dep;
    48         return;
    49     }
    50     int m = (l + r) >> 1;
    51     if (pos <= m) add(seg[p].ls, l, m, pos);
    52     else add(seg[p].rs, m + 1, r, pos);
    53 }
    54  
    55 int query(int p, int l, int r, int pos){
    56     if (l == r) return p;
    57     int m = (l + r) >> 1;
    58     if (pos <= m) return query(seg[p].ls, l, m, pos);
    59     else return query(seg[p].rs, m + 1, r, pos);
    60 }
    61  
    62 int find(int p, int x){
    63     int k = query(p, 1, n, x);
    64     if (x == seg[k].v) return k;
    65     int t = find(p, seg[k].v);
    66     modify(1, n, p, p, seg[k].v, t);
    67     return t;
    68 }
    69  
    70 int main(){
    71     scanf("%d %d
    ", &n, &m);
    72     build_seg(root[0], 1, n);
    73     int oper, x, y, p, q;
    74     for(int i = 1; i <= m; ++i){
    75         scanf("%d", &oper);
    76         if (oper == 1){
    77             scanf("%d%d", &x, &y);
    78             x = x ^ last, y = y ^ last;
    79             root[i] = root[i - 1];
    80             p = find(root[i], x), q = find(root[i], y);
    81             if (seg[p].v == seg[q].v) continue;
    82             if (seg[p].dep > seg[q].dep) swap(p, q);
    83             modify(1, n, root[i - 1], root[i], seg[p].v, seg[q].v);
    84             if (seg[p].dep == seg[q].dep) add(root[i], 1, n, seg[q].v);
    85         } else if (oper == 2){
    86             scanf("%d", &x);
    87             x = x ^ last;
    88             root[i] = root[x];
    89         } else{
    90             scanf("%d%d", &x ,&y);
    91             x = x ^ last, y = y ^ last;
    92             root[i] = root[i - 1];
    93             p = find(root[i], x), q = find(root[i], y);
    94             if (seg[p].v == seg[q].v) last = 1; else last = 0;
    95             printf("%d
    ", last);
    96         }
    97     }
    98     return 0;
    99 }
    View Code

    (p.s. 作为一名典型的嘴巴选手,还是要Orz hzwer的程序!!!)

    By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
  • 相关阅读:
    Spring中的AOP
    P2782 友好城市
    1576 最长严格上升子序列
    1058 合唱队形 2004年NOIP全国联赛提高组
    5294 挖地雷
    1643 线段覆盖 3
    4768 跳石头
    1026 逃跑的拉尔夫
    2727:仙岛求药
    codevs 4888 零件分组
  • 原文地址:https://www.cnblogs.com/rausen/p/4006147.html
Copyright © 2011-2022 走看看