[AHOI2005] 航线规划 - LCT

Description

给定一张无向图,每次删除一条边,每次询问两点间短程线上桥的数量

Solution

删除类问题时间倒流转化为加边

用 LCT 维护一个支撑树

对于每条树边维护一个权值,支持区间覆盖为 0

加边时,如果真的加在 LCT 上了把这个权值设为 1,如果没有加上,则把对应树上路径上的边权全部覆盖为 0

这样询问的答案就是对应树上路径的边权和

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000000;

int n,m,val[N];

namespace lct {
	int top, q[N], ch[N][2], fa[N], rev[N], sum[N], tag[N];
	inline void pushup(int x){
		sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x];
	}
	inline void puttag(int x) {
	    if(!x) return;
        tag[x]=1;
        sum[x]=0;
        val[x]=0;
	}
	inline void pushdown(int x){
	    if(tag[x]) {
            puttag(ch[x][0]);
            puttag(ch[x][1]);
            tag[x]=0;
	    }
		if(!rev[x]) return;
		rev[ch[x][0]]^=1;
		rev[ch[x][1]]^=1;
		rev[x]^=1;
		swap(ch[x][0],ch[x][1]);
	}
	inline bool isroot(int x){
		return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
	}
	inline void rotate(int p){
		int q=fa[p], y=fa[q], x=ch[fa[p]][1]==p;
		ch[q][x]=ch[p][x^1]; fa[ch[q][x]]=q;
		ch[p][x^1]=q; fa[q]=p; fa[p]=y;
		if(y) if(ch[y][0]==q) ch[y][0]=p;
		else  if(ch[y][1]==q) ch[y][1]=p;
		pushup(q); pushup(p);
	}
	inline void splay(int x){
		q[top=1]=x;
		for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
		for(int i=top;i;i--) pushdown(q[i]);
		for(;!isroot(x);rotate(x))
			if(!isroot(fa[x]))
				rotate((ch[fa[x]][0]==x)==(ch[fa[fa[x]]][0]==fa[x])?fa[x]:x);
	}
	void access(int x){
		for(int t=0;x;t=x,x=fa[x])
			splay(x),ch[x][1]=t,pushup(x);
	}
	void makeroot(int x){
		access(x);
		splay(x);
		rev[x]^=1;
	}
	int find(int x){
		access(x);
		splay(x);
		while(ch[x][0]) x=ch[x][0];
		return x;
	}
	void split(int x,int y){
		makeroot(x);
		access(y);
		splay(y);
	}
	void cut(int x,int y){
		split(x,y);
		if(ch[y][0]==x)
			ch[y][0]=0, fa[x]=0;
	}
	void link(int x,int y){
		makeroot(x);
		fa[x]=y;
		pushup(y);
	}
	int query(int x,int y) {
	    if(find(x)!=find(y)) return 0;
        split(x,y);
        return sum[y];
	}
	void modify(int x,int y) {
        split(x,y);
        puttag(y);
	}
}

struct edge {
    int u,v;
    edge() {
        u=v=0;
    }
    edge(int a,int b) {
        u=min(a,b);
        v=max(a,b);
    }
    bool operator < (const edge &x) const {
        return u==x.u ? v<x.v : u<x.u;
    }
    bool operator == (const edge &x) const {
        return u==x.u && v==x.v;
    }
} ed[N];

map<int,int> mp;
int t1,t2,t3,ind,fg[N];

struct operating {
    int op,u,v;
};

int idedge(int u,int v) {
    if(u>v) swap(u,v);
    return u*N+v;
}

vector <operating> vec;
vector <int> ans;

void linkedge(int i) {
    if(lct::find(ed[i].u)==lct::find(ed[i].v)) {
        lct::modify(ed[i].u,ed[i].v);
    }
    else {
        lct::link(ed[i].u,i);lct::link(ed[i].v,i);
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    ind=n;
    for(int i=1;i<=m;i++) {
        cin>>t1>>t2;
        mp[idedge(t1,t2)]=++ind;
        ed[ind]=edge(t1,t2);
    }
    while(true) {
        cin>>t1;
        if(t1==-1) {
            break;
        }
        cin>>t2>>t3;
        vec.push_back({t1,t2,t3});
        if(t1==0) {
            fg[mp[idedge(t2,t3)]]=1;
        }
    }
    reverse(vec.begin(),vec.end());
    for(int i=n+1;i<=n+m;i++) {
        val[i]=1;
    }
    for(int i=n+1;i<=n+m;i++) {
        if(fg[i]==0) {
            linkedge(i);
        }
    }
    for(operating now:vec) {
        if(now.op==0) {
            int i=mp[idedge(now.u,now.v)];
            linkedge(i);
        }
        else {
            ans.push_back(lct::query(now.u,now.v));
        }
    }
    while(ans.size()) {
        cout<<*ans.rbegin()<<endl;
        ans.pop_back();
    }
}



猜你喜欢

转载自www.cnblogs.com/mollnn/p/13187342.html
今日推荐