zoukankan      html  css  js  c++  java
  • [AHOI2005] 航线规划

    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();
        }
    }
    
    
    
    
  • 相关阅读:
    关于DRY原则
    类型之惑
    ThoughtWorks测试
    编程非易事
    瀑布与迭代的真实区别
    对TDD原则的理解
    自我练习
    C# CreateProcess的测试
    乱侃OOD
    复杂系统的五个属性
  • 原文地址:https://www.cnblogs.com/mollnn/p/13187342.html
Copyright © 2011-2022 走看看