卧薪尝胆,厚积薄发。
      
    
            AHOI2005 航线规划
        
        
        Description:
给定一个图,每次删除一条边或查询两点之间桥的数目,保证任意时刻图联通
$ 1 \le N \le 30000 $
 
$ 1 \le M \le 100000 $
 
$ 1 \le Q \le 40000 $
Solution:
离线处理倒序加边,
$ LCT $
维护边双连通分量,在加边时如果已经形成了一个环,就取出环递归将它缩成一个点,如果新加的边两点已经联通,就将一个点
$makeroot$
,另一个点
$access$
,得到的辅助树即为这个环,缩点的过程用一个并查集来维护缩点后的点,在输出时桥的个数就是路径上点的个数-1
注意在
$access$
时循环里
$ k = t[k].fa $
要改成
$ k = t[k].fa = find(t[k].fa) $
因为此时
$ t[k].fa $
已经被替换成了
$ find(t[k].fa) $
所以在跳的时候顺便修改
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<cstring>
using namespace std;
int read(){
    int res = 0,f;
    char c = getchar();
    while(!isdigit(c) && c != '-')c = getchar();
    if(c == '-'){f = -1;c = getchar();}
    else f = 1;
    while(isdigit(c))
    {
        res = (res << 1) + (res << 3) + c - '0';
        c = getchar();
    }
    return res * f;
}
int n,m,q = 0;
#define MAXN 30010
#define MAXM 100010
#define MAXQ 40010
int f[MAXN];
int find(int x){return (x == f[x] ? x : (f[x] = find(f[x])));}
struct node
{
    int c[2],fa,siz;
    bool rev;
    node(){c[0] = c[1] = fa = 0;rev = false;}
}t[MAXN];
void maintain(int rt)
{
    t[rt].siz = 1;
    if(t[rt].c[0] != 0)t[rt].siz += t[t[rt].c[0]].siz;
    if(t[rt].c[1] != 0)t[rt].siz += t[t[rt].c[1]].siz;
    return;
}
bool isroot(int rt){return (t[t[rt].fa].c[0] != rt && t[t[rt].fa].c[1] != rt);}
int id(int rt){return (t[t[rt].fa].c[0] == rt ? 0 : 1);}
void connect(int k,int f,int p){t[k].fa = f;t[f].c[p] = k;return;}
void pushdown(int rt)
{
    if(!t[rt].rev)return;
    t[t[rt].c[0]].rev ^= 1;t[t[rt].c[1]].rev ^= 1;
    swap(t[rt].c[0],t[rt].c[1]);t[rt].rev = false;
    return;
}
void rotate(int x)
{
    int y = t[x].fa,z = t[y].fa,fx = id(x),fy = id(y);
    if(!isroot(y))t[z].c[fy] = x;
    t[x].fa = z;
    connect(t[x].c[fx^1],y,fx);
    connect(y,x,fx^1);
    maintain(y);maintain(x);
    return;
}
stack<int> s;
void splay(int x)
{
    s.push(x);
    for(int i = x;!isroot(i);i = t[i].fa){s.push(t[i].fa);}
    while(!s.empty()){pushdown(s.top());s.pop();}
    while(!isroot(x))
    {
        int y = t[x].fa;
        if(isroot(y)){rotate(x);break;}
        if(id(x) == id(y)){rotate(y);rotate(x);}
        else{rotate(x);rotate(x);}
    }
    return;
}
void access(int k){for(int i = 0;k != 0;i = k,k = t[k].fa = find(t[k].fa)){splay(k);t[k].c[1] = i;maintain(k);}return;}
void makeroot(int k){access(k);splay(k);t[k].rev ^= 1;return;}
void link(int x,int y){makeroot(x);makeroot(y);t[x].fa = y;return;}
int root(int x){access(x);splay(x);while(true){pushdown(x);if(t[x].c[0] != 0)x = t[x].c[0];else return x;}}
void pre(int x,int y){makeroot(x);access(y);splay(y);return;}
struct line
{
    int u,v;
    bool tag;
}l[MAXM];
map<pair<int,int>,bool> p;
struct question
{
    int type,u,v;   
}r[MAXQ];
void remove(int rt,int tp)
{
    if(rt == 0)return;
    f[rt] = tp;
    remove(t[rt].c[0],tp);remove(t[rt].c[1],tp);
    t[rt].c[0] = t[rt].c[1] = 0;
    return;
}
void merge(int x,int y)
{
    if(x == y)return;
    if(root(x) != root(y)){link(x,y);return;}
    else{makeroot(x);access(y);splay(x);remove(x,x);maintain(x);}
    return;
}
int ans[MAXQ];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i)f[i] = i;
    for(int i = 1;i <= m;++i)
    {
        l[i].u = read();l[i].v = read();if(l[i].u > l[i].v)swap(l[i].u,l[i].v); 
        p[make_pair(l[i].u,l[i].v)] = p[make_pair(l[i].v,l[i].u)] = true;
    }
    int a;
    while(true)
    {
        scanf("%d",&a);if(a == -1)break;r[++q].type = a;
        scanf("%d%d",&r[q].u,&r[q].v);if(r[q].u > r[q].v)swap(r[q].u,r[q].v);
        if(a == 0)p[make_pair(r[q].u,r[q].v)] = p[make_pair(r[q].v,r[q].u)] = false;
    }
    for(int i = 1;i <= m;++i)if(p[make_pair(l[i].u,l[i].v)])merge(find(l[i].u),find(l[i].v));
    for(int i = q;i >= 1;--i)
    {
        r[i].u = find(r[i].u);r[i].v = find(r[i].v);
        if(r[i].type == 0)merge(r[i].u,r[i].v);
        else
        {
            if(r[i].u == r[i].v){ans[i] = 0;continue;}
            pre(r[i].u,r[i].v);
            ans[i] = t[r[i].v].siz - 1;
        }
    }
    for(int i = 1;i <= q;++i)if(r[i].type == 1)printf("%d\n",ans[i]);
    return 0;
}
          In tag:
数据结构-LCT 
          
        
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
    
          Date: Wed May 23 11:01:30 CST 2018
          
          In Category:
          
        
            Timeline
          
            About
          
            Toolbox
          
              Friends