[題解] bzoj 3674 可持久化並查集增強版

- 傳送門 -

 http://www.lydsy.com/JudgeOnline/problem.php?id=3674
 php

3674: 可持久化並查集增強版

Time Limit: 15 Sec  Memory Limit: 256 MB
Submit: 4218  Solved: 1557優化

Description

自從zkysb出了可持久化並查集後……
hzwer:亂寫能AC,暴力踩標程
KuribohG:我不路徑壓縮就過了!
ndsf:暴力就能夠輕鬆虐!
zky:……ui

n個集合 m個操做
操做:
1 a b 合併a,b所在集合
2 k 回到第k次操做以後的狀態(查詢算做操做)
3 a b 詢問a,b是否屬於同一集合,是則輸出1不然輸出0
請注意本題採用強制在線,所給的a,b,k均通過加密,加密方法爲x = x xor lastans,lastans的初始值爲0
0<n,m<=2*10^5加密

Sample Input

5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2spa

Sample Output

1
0
1  code

- 思路 -

未增強的在3673,可是啥優化都不加也能過.
而後作到這題我才發現並查集有種叫按秩合併的優化...我是傻子嗎...
看了第一篇講解說就是把rank小的接在大的下面
可是rank是什麼....
因而我就把編號小的接在大的下面...而後就過了...
但是這和我看到的AC代碼好像不同...
而後又看了一篇講解,發現按秩合併是指把數量小的樹接到大的上去,一般是用高度來取代這個數量
...
哦我終於看懂了標程了...
再打一遍,而後發現慢了一倍...
哦仔細想一想按編號來優化也是能夠的,除非是8,7,6,5,4,3,2,1這樣倒着合併會合出一條鏈,可是大部分狀況下仍是可行的,並且也不須要維護什麼東西(大概就是這裏節省了時間).
路徑壓縮...不存在的...怎麼可能說我懶得打ip

 細節見代碼.
 get

- 代碼 -

按編號優化:input

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <ctime>
#include <cstdlib>
#define pii pair<int, int>
#define mp make_pair
#define ft first
#define sd second
#define ls C[rt][0]
#define rs C[rt][1]
using namespace std;

template <typename ty> void read(ty &x) {
  x = 0; int f = 1; char ch = getchar();
  while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
  while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
  x *= f;
}
template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; }
template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; }
template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; }
template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; }

typedef long long LL;
typedef double db;

const int inf = 0x7fffffff;
const int N = 2e5 + 16;

int F[N], V[N*20], C[N*20][2], RT[N], P[N];
int n, m, sz, lastans;

void build(int &rt, int l, int r) {
  rt = ++sz;
  if (l == r) { V[rt] = l; return; }
  int mid = l + r >> 1;
  build(C[rt][0], l, mid);
  build(C[rt][1], mid + 1, r);
}

int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); }

int query(int rt, int l, int r, int pos) {
  if (l == r) return V[rt];
  int mid = l + r >> 1;
  if (pos <= mid) return query(C[rt][0], l, mid, pos);
  else return query(C[rt][1], mid + 1, r, pos);
}

void change(int &now, int pre, int l, int r, int pos, int v) {
  now = ++sz;
  C[now][0] = C[pre][0]; C[now][1] = C[pre][1];
  if (l == r) { V[now] = v; return; }
  int mid = l + r >> 1;
  if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v);
  else change(C[now][1], C[pre][1], mid + 1, r, pos, v);
}

int get(int rt, int a) {
  int tmp = a;
  while (true) {
    tmp = query(RT[rt], 1, n, tmp);
    if (query(RT[rt], 1, n, tmp) != tmp)
      a = tmp;
    else return tmp;
  }
}

int main () {

  read(n); read(m);
  build(RT[0], 1, n);

  for (int i = 1; i <= m; ++ i) {
    F[i] = i;
    int opt, a, b, k;
    read(opt);
    if (opt == 1) {
      read(a); read(b);
      a ^= lastans, b ^= lastans;
      int pre = find(i - 1);
      int tmp1, tmp2;
      tmp1 = get(pre, a);
      tmp2 = get(pre, b);
      if (tmp1 == tmp2) { F[i] = i - 1; continue; }
      if (tmp1 < tmp2) swap(tmp1, tmp2);
      change(RT[i], RT[pre], 1, n, tmp1, tmp2);
    }
    if (opt == 2) {
      read(k);
      k ^= lastans;
      F[i] = find(k);
    }
    if (opt == 3) {
      F[i] = find(i - 1);
      read(a); read(b);
      a ^= lastans, b ^= lastans;
      int tmp, tmp1, tmp2;
      tmp1 = get(F[i], a);
      tmp2 = get(F[i], b);
      if (tmp1 == tmp2) lastans = 1, printf("1\n");
      else lastans = 0, printf("0\n");
    }
  }


  return 0;

}

按秩合併:string

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <ctime>
#include <cstdlib>
#define pii pair<int, int>
#define mp make_pair
#define ft first
#define sd second
#define ls C[rt][0]
#define rs C[rt][1]
using namespace std;

template <typename ty> void read(ty &x) {
  x = 0; int f = 1; char ch = getchar();
  while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
  while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
  x *= f;
}
template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; }
template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; }
template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; }
template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; }

typedef long long LL;
typedef double db;

const int inf = 0x7fffffff;
const int N = 2e5 + 16;

int F[N], V[N*20], C[N*20][2], D[N*20], RT[N], P[N];
int n, m, sz, lastans;

void build(int &rt, int l, int r) {
  rt = ++sz;
  if (l == r) { V[rt] = l; return; }
  int mid = l + r >> 1;
  build(C[rt][0], l, mid);
  build(C[rt][1], mid + 1, r);
}

int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); }

int query(int rt, int l, int r, int pos) {
  if (l == r) return V[rt];
  int mid = l + r >> 1;
  if (pos <= mid) return query(C[rt][0], l, mid, pos);
  else return query(C[rt][1], mid + 1, r, pos);
}

void change(int &now, int pre, int l, int r, int pos, int v) {
  now = ++sz;
  C[now][0] = C[pre][0]; C[now][1] = C[pre][1];
  if (l == r) { V[now] = v; return; }
  int mid = l + r >> 1;
  if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v);
  else change(C[now][1], C[pre][1], mid + 1, r, pos, v);
}

int get(int rt, int a) {
  int tmp = a;
  while (true) {
    tmp = query(RT[rt], 1, n, tmp);
    if (query(RT[rt], 1, n, tmp) != tmp)
      a = tmp;
    else return tmp;
  }
}

void add(int rt, int l, int r, int pos) {
  if (l == r) { D[rt] ++; return; }
  int mid = l + r >> 1;
  if (pos <= mid) add(C[rt][0], l, mid, pos);
  else add(C[rt][1], mid + 1, r, pos);
}

int main () {

  read(n); read(m);
  build(RT[0], 1, n);

  for (int i = 1; i <= m; ++ i) {
    F[i] = i;
    int opt, a, b, k;
    read(opt);
    if (opt == 1) {
      read(a); read(b);
      a ^= lastans, b ^= lastans;
      int pre = find(i - 1);
      int tmp1, tmp2;
      tmp1 = get(pre, a);
      tmp2 = get(pre, b);
      if (tmp1 == tmp2) { F[i] = i - 1; continue; }
      if (D[tmp1] > D[tmp2]) swap(tmp1, tmp2);
      change(RT[i], RT[pre], 1, n, tmp1, tmp2);
      if (D[tmp1] == D[tmp2]) add(RT[i], 1, n, tmp2);
    }
    if (opt == 2) {
      read(k);
      k ^= lastans;
      F[i] = find(k);
    }
    if (opt == 3) {
      F[i] = find(i - 1);
      read(a); read(b);
      a ^= lastans, b ^= lastans;
      int tmp, tmp1, tmp2;
      tmp1 = get(F[i], a);
      tmp2 = get(F[i], b);
      if (tmp1 == tmp2) lastans = 1, printf("1\n");
      else lastans = 0, printf("0\n");
    }
  }


  return 0;

}
相關文章
相關標籤/搜索