• #线段树分治,线性基,并查集#CF938G Shortest Path Queries


    题目

    给出一个连通带权无向图,边有边权,要求支持 (q) 个操作:

    1. (x) (y) (d) 在原图中加入一条 (x)(y) 权值为 (b) 的边

    2. (x) (y) 把图中 (x)(y) 的边删掉

    3. (x) (y) 表示询问 (x)(y) 的异或最短路

    保证任意操作后原图连通无重边自环且操作均合法

    (n,m,q≤200000)


    分析

    删除很难做,考虑线段树分治,
    那么题目就转换成求某一时间点,
    无向图的异或最短路,先构建一棵生成树,
    那么环上边等于是将生成树异或值抵消掉,
    用线性基求异或最小值
    那么在并查集的基础上维护生成树点到根的距离即可


    代码

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <cstring>
    #include <map>
    #define rr register
    using namespace std;
    const int N=200011; vector<int>K[N<<2]; struct five{int x,y,w,l,r;}e[N<<1];
    struct rec{int x,y;}q[N]; map<pair<int,int>,int>uk;
    int n,m,T,dep[N],f[N],d[N],stac[N],stad[N],tac[N],tad[N],staD[N],taD[N],tot,tod,toD,ans[N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    struct Vector_Space{
    	int re[30];
    	inline void BUILD(){memset(re,0,sizeof(re));}
    	inline void Insert(int x){
    		for (rr int i=29;~i;--i)
    		if ((x>>i)&1){
    			if (re[i]) x^=re[i];
    			    else {re[i]=x; return;}
    		}
    	}
    	inline signed query(int x){
    		for (rr int i=29;~i;--i)
    		    if ((x^re[i])<x) x^=re[i];
    		return x;
    	}
    };
    inline void update(int k,int l,int r,int x,int y,int z){
    	if (l==x&&r==y) {K[k].push_back(z); return;}
    	rr int mid=(l+r)>>1;
    	if (y<=mid) update(k<<1,l,mid,x,y,z);
    	else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
    	    else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
    }
    inline signed getf(int u){return f[u]==u?u:getf(f[u]);}
    inline signed getd(int u){return f[u]==u?0:(d[u]^getd(f[u]));}
    inline void dfs(int k,int l,int r,Vector_Space H){
    	rr int len=K[k].size(),Tot=tot,Tod=tod,ToD=toD;
    	for (rr int i=0;i<len;++i){
    		rr five t=e[K[k][i]];
    		rr int fa=getf(t.x),fb=getf(t.y);
    		rr int W=getd(t.x)^getd(t.y)^t.w;
    		if (fa==fb){H.Insert(W); continue;}
    		if (dep[fa]>dep[fb]) fa^=fb,fb^=fa,fa^=fb;
    		staD[++toD]=fa,taD[toD]=d[fa],d[fa]=W;
    		if (dep[fa]==dep[fb]){
    			stad[++tod]=fb,tad[tod]=dep[fb];
    			++dep[fb];
    	    }
    	    stac[++tot]=fa,tac[tot]=f[fa],f[fa]=fb;		
    	}
    	rr int mid=(l+r)>>1;
    	if (l==r) ans[l]=H.query(getd(q[l].x)^getd(q[l].y));
    	    else dfs(k<<1,l,mid,H),dfs(k<<1|1,mid+1,r,H);
        for (;tot>Tot;--tot) f[stac[tot]]=tac[tot];
        for (;tod>Tod;--tod) dep[stad[tod]]=tad[tod];
        for (;toD>ToD;--toD) d[staD[toD]]=taD[toD];
    }
    signed main(){
    	n=iut(),m=iut();
    	for (rr int i=1;i<=n;++i) f[i]=i,dep[i]=1;
    	for (rr int i=1;i<=m;++i){
    		rr int x=iut(),y=iut(),w=iut();
    		if (x>y) x^=y,y^=x,x^=y;
    		e[i]=(five){x,y,w,0,-2},uk[make_pair(x,y)]=i;
    	}
    	for (rr int Q=iut();Q;--Q){
    		rr int opt=iut(),x=iut(),y=iut();
    		if (x>y) x^=y,y^=x,x^=y;
    		if (opt==1)
    			e[++m]=(five){x,y,iut(),T,-2},
    			    uk[make_pair(x,y)]=m;
    		else if (opt==2){
    			rr int now=uk[make_pair(x,y)];
    			e[now].r=T-1;
    		}else q[T++]=(rec){x,y};
    	}
    	for (rr int i=1;i<=m;++i) if (e[i].r==-2) e[i].r=T;
    	for (rr int i=1;i<=m;++i)
    	    if (e[i].l<=e[i].r) update(1,0,T,e[i].l,e[i].r,i);
    	rr Vector_Space H; H.BUILD(),dfs(1,0,T,H);
    	for (rr int i=0;i<T;++i) print(ans[i]),putchar(10);
    	return 0;
    }
    
  • 相关阅读:
    [转] zigbee的低功耗
    手机显示电量原理
    TinyOS总结(一)
    KingPaper初探redist 之redis设置分析
    KingPaper初探redis之redis在window xp下的安装
    Web开发必知的八种隔离级别
    目前国内著名的维客(wiki)网站
    SSH Secure Shell Client
    Java线程:volatile关键字
    JDK1.6(JDK6.0) 新特性
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14911873.html
Copyright © 2020-2023  润新知