BZOJ 2564 水管局长加强版

给出一个 n n n个点 m m m条边的无向图,每个询问会让你删除一条 x , y x,y x,y的边

或者是询问你 x , y x,y x,y间路径最大值的最小值。

n , q ≤ 1 0 5 , m ≤ 1 0 6 , l i m i t : 2500 m s n,q\leq 10^5,m\leq10^6,limit:2500ms n,q105,m106,limit:2500ms

此题是加强版。LCT会不会被卡到挂啊?

但是我并没有写加强版(雾

sol:

实际上对于原版来说不同的是点的数量,也就是说你需要用个map之类的东西维护一下,

而不是直接套邻接矩阵。

对于删边我们把它变成加边,就成了增量生成树问题。

然后就是 L C T LCT LCT维护 M S T MST MST的板子题了:对于点 x , y x,y x,y L C T LCT LCT拉出路径上的最大值,

和当前新加的边比较一下是不是要断掉。

我们选择把边权转点权,方法是两个点拆成三个,中间一个虚点赋值。

数据结构题好久没有在没拍的情况下1A了。

#include
#include
#include
#define debug printf("GG\n")
const int N = 3e5 + 7;
int s[N], v[N]; 
inline int max(int a, int b) {return a > b ? a : b;}
inline int ckmax(int a, int b) {return v[a] > v[b] ? a : b;}
struct LCT {
  int rev[N], w[N], f[N], ch[N][2], siz[N], mx[N];
  #define lc ch[x][0]
  #define rc ch[x][1]
  #define sp(a, b) std :: swap(a, b)
  inline int getwho(int x) {return ch[f[x]][0] == x ? 0 : 1;}
  inline void pushup(int x) {mx[x] = ckmax(x, ckmax(mx[lc], mx[rc]));}
  inline void resv(int x) {sp(lc, rc), rev[x] ^= 1;}
  inline int nort(int x) {return ch[f[x]][0] == x || ch[f[x]][1] == x;}
  inline void Rotate(int x) {
    int fa = f[x], gra = f[f[x]], who = getwho(x);
    if (nort(fa)) ch[gra][getwho(fa)] = x;
    f[x] = gra;
    ch[fa][who] = ch[x][who ^ 1], f[ch[x][who ^ 1]] = fa;
    ch[x][who ^ 1] = fa, f[fa] = x;
    pushup(fa), pushup(x);
  }
  inline void pushdown(int x) {
    if (rev[x]) {
      if (lc) resv(lc);
      if (rc) resv(rc);
      rev[x] = 0;
    }
  }
  inline void splay(int x) {
    int o = x, cnt = 0;
    s[++cnt] = o;
    while (nort(o)) s[++cnt] = (o = f[o]);
    while (cnt) pushdown(s[cnt--]);
    while (nort(x)) {
      int fa = f[x];
      if (nort(fa)) 
        Rotate(getwho(fa) == getwho(x) ? fa : x);
      Rotate(x);
    } 
  }
  inline void access(int x) {
    for (int y = 0; x; y = x, x = f[x]) 
      splay(x), rc = y, pushup(x);
  }
  inline void bert(int x) {access(x), splay(x), resv(x);}
  inline int findrt(int x) {
    access(x), splay(x); 
    while (lc) pushdown(x), x = lc;
    splay(x);return x;
  }
  inline void split(int x, int y) {bert(x), access(y), splay(y);}
  inline int link(int x, int y) {
    bert(x);
    if (findrt(y) == x) return 0;
    f[x] = y; return 1;
  }
  inline int cut(int x, int y) {
    bert(x);
    if (findrt(y) != x || f[y] != x /*|| ch[x][0] != y*/) return 0;
    f[y] = ch[x][1] = 0, pushup(x);
    return 1;
  }
}t; int n, m, Q, tot;
const int upNode = 3e3+7;
struct Edge {int from, to, id;} e[N*2];
int cNode[N][2], pcnt, map[upNode][upNode];
struct Question {int opt, x, y;} q[N*2];
int ff[N], size[N];
inline int find(int x) {
  if (ff[x] == x) return x;
  ff[x] = find(ff[x]); 
  return ff[x];
}
inline int Union(int x, int y) {
 // debug;
  int a = find(x), b = find(y);
  if (a == b) return 0;
  if (size[a] > size[b]) ff[b] = a;
  else if (size[a] == size[b]) ff[b] = a, size[a]++;
  else ff[a] = b;
  return 1;
}
struct res {int st, to, w, id;} eres[N*2];
inline int cmp(res a, res b) {return a.w < b.w;}
int orgi[N*2];
void init() {
  scanf("%d%d%d", &n, &m, &Q);
  for (int i = 1; i <= 3e5; i++) ff[i] = i;
  for (int i = 1; i <= m; i++) {
    int x, y, z; 
    scanf("%d%d%d", &x, &y, &z);
    if (x > y) std :: swap(x, y);
    eres[i].st = x, eres[i].to = y, eres[i].w = z;
    e[++tot].from = x, 
    e[tot].to = i;
    e[++tot].from = i, 
    e[tot].to = y;
    v[i + n] = z;
    cNode[i + n][0] = x, cNode[i + n][1] = y;
    eres[i].id = i + n;
  }
  for (int i = 1; i <= Q; i++) {
    scanf("%d%d%d", &q[i].opt, &q[i].x, &q[i].y);
    if (q[i].x > q[i].y) std :: swap(q[i].x, q[i].y);
    if (q[i].opt == 2) map[q[i].x][q[i].y] = 1;
  }
  std :: sort(eres + 1, eres + m + 1, cmp);
  int ptot = 0;
  for (int i = 1; i <= m; i++) {
    int a = find(eres[i].st), b = find(eres[i].to);
    if (a == b || map[eres[i].st][eres[i].to]) continue;
    Union(a, b);
    t.link(eres[i].st, eres[i].id), t.link(eres[i].id, eres[i].to); 
    ptot++;
    if (ptot == n - 1) break;
  }
  for (int i = 1; i <= m; i++) 
    if (map[e[i * 2 - 1].from][e[i * 2].to]) 
      map[e[i * 2 - 1].from][e[i * 2].to] = i + n;
} int stack[N]; int opts;
void solve() {
  for (int i = Q; i >= 1; i--) {
    if (q[i].opt == 2) {
      //debug;
      t.split(q[i].x, q[i].y);
     // debug;
      int o = t.mx[q[i].y];
      if (v[o] > v[map[q[i].x][q[i].y]])
        t.cut(cNode[o][0], o), t.cut(o, cNode[o][1]),
        t.link(q[i].x, map[q[i].x][q[i].y]), t.link(map[q[i].x][q[i].y], q[i].y);
      else continue;
    } else {
   //   debug;
      t.split(q[i].x, q[i].y);
      stack[++opts] = v[t.mx[q[i].y]];
    }
  }
  while (opts) printf ("%d\n", stack[opts--]);
}
int main() {
  init();
  //debug;
  solve();
}

你可能感兴趣的:(LCT,生成树)