zoukankan      html  css  js  c++  java
  • [VIJOS2053][SDOI2019]世界地图:最小生成树+虚树

    分析

    可以发现第一列和最后一列永远不会被删除,于是我们可以想到维护前后缀最小生成树,但是直接维护的话显然时间空间两爆炸。(通过上网找题解)可以发现我们关心的只是最左边和最右边两列,而不关心内部的连边情况。所以我们可以仅维护这两列的节点在最小生成树上形成的虚树,边权是对应链上最大的边权,合并时对两棵虚树上的所有边再跑一遍最小生成树就好了。

    由于虚树的大小是(O(n))级别的,所以该算法的时间复杂度为(O(n(m+q) log n))

    这代码写起来有点恶心。

    代码

    #include <bits/stdc++.h>
    
    #define rin(i,a,b) for(int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(int i=(a);i>=(b);--i)
    #define trav(i,a) for(int i=head[a];i;i=e[i].nxt)
    #define Size(a) (int)a.size()
    #define pb push_back
    #define mkpr std::make_pair
    #define fi first
    #define se second
    #define lowbit(a) ((a)&(-(a)))
    typedef long long LL;
    
    using std::cerr;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=105;
    const int MAXM=10005;
    
    int n,m,q;
    unsigned int SA, SB, SC;int lim;
    
    int getweight() {
        SA ^= SA << 16;
        SA ^= SA >> 5;
        SA ^= SA << 1;
        unsigned int t = SA;
        SA = SB;
        SB = SC;
        SC ^= t ^ SA;
        return SC % lim + 1;
    }
    
    struct mst_edge{
    	int u,v,w;
    	inline friend bool operator < (mst_edge x,mst_edge y){
    		return x.w<y.w;
    	}
    };
    
    struct mst{
    	LL sum;
    	std::vector<int> poi;
    	std::vector<mst_edge> edg;
    	inline void init(){sum=0;poi.clear();edg.clear();}
    };
    
    mst pre[MAXM],suf[MAXM];
    std::vector<mst_edge> hng[MAXM],shu[MAXM],ext;
    
    inline int calc_id(int x,int y){
    	return (x-1)*m+y;
    }
    
    int dsu[MAXN*MAXM];
    int ecnt,head[MAXN*MAXM];
    bool mark[MAXN*MAXM],havem[MAXN*MAXM];
    std::vector<int> po,retp;
    std::vector<mst_edge> ee,rete;
    
    struct Edge{
    	int to,nxt,w;
    }e[MAXN*MAXM*4];
    
    int getf(int x){
    	return dsu[x]==x?x:dsu[x]=getf(dsu[x]);
    }
    
    inline bool merge_dsu(int x,int y){
    	x=getf(x),y=getf(y);
    	if(x!=y){
    		dsu[y]=x;
    		return true;
    	}
    	return false;
    }
    
    inline void add_edge(int bg,int ed,int val){
    	++ecnt;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	e[ecnt].w=val;
    	head[bg]=ecnt;
    }
    
    void dfs1(int x,int pre){
    	havem[x]|=mark[x];
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre)continue;
    		dfs1(ver,x);
    		havem[x]|=havem[ver];
    	}
    }
    
    void dfs2(int x,int pre,int las,int maxw){
    	int flag=0;
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre)continue;
    		if(havem[ver])++flag;
    	}
    	if(flag>1)mark[x]=true;
    	if(mark[x]){
    		retp.pb(x);
    		if(las)rete.pb((mst_edge){las,x,maxw});
    	}
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre)continue;
    		if(mark[x])dfs2(ver,x,x,e[i].w);
    		else dfs2(ver,x,las,std::max(maxw,e[i].w));
    	}
    }
    
    mst merge(mst L,mst R,int bg){
    	mst ret;ret.init();
    	ret.sum=L.sum+R.sum;
    	po.clear();ee.clear();
    	retp.clear();rete.clear();ecnt=0;
    	rin(i,0,Size(L.poi)-1)po.pb(L.poi[i]);
    	rin(i,0,Size(R.poi)-1)po.pb(R.poi[i]);
    	rin(i,0,Size(L.edg)-1){
    		ret.sum-=L.edg[i].w;
    		ee.pb(L.edg[i]);
    	}
    	rin(i,0,Size(R.edg)-1){
    		ret.sum-=R.edg[i].w;
    		ee.pb(R.edg[i]);
    	}
    	rin(i,0,Size(ext)-1)ee.pb(ext[i]);
    	rin(i,0,Size(po)-1){
    		dsu[po[i]]=po[i];
    		head[po[i]]=0;
    		mark[po[i]]=havem[po[i]]=false;
    	}
    	std::sort(ee.begin(),ee.end());
    	int temp=0;
    	rin(i,0,Size(ee)-1){
    		if(merge_dsu(ee[i].u,ee[i].v)){
    			++temp;
    			ret.sum+=ee[i].w;
    			add_edge(ee[i].u,ee[i].v,ee[i].w);
    			add_edge(ee[i].v,ee[i].u,ee[i].w);
    			if(temp==Size(po)-1)break;
    		}
    	}
    	rin(i,1,n)mark[calc_id(i,bg)]=true;
    	if(bg==1)rin(i,0,Size(R.poi)-1)mark[R.poi[i]]=true;
    	else rin(i,0,Size(L.poi)-1)mark[L.poi[i]]=true;
    	dfs1(po[0],0);dfs2(po[0],0,0,0);
    	ret.poi=retp,ret.edg=rete;
    	return ret;
    }
    
    int main(){
    	n=read(),m=read(),SA=read(),SB=read(),SC=read(),lim=read();
    	rin(i,1,n)rin(j,1,m){
    		int w=getweight();
    		if(j<m)hng[j].pb((mst_edge){calc_id(i,j),calc_id(i,j+1),w});
    		else hng[j].pb((mst_edge){calc_id(i,j),calc_id(i,1),w});
    	}
    	rin(i,1,n-1)rin(j,1,m){
    		int w=getweight();
    		shu[j].pb((mst_edge){calc_id(i,j),calc_id(i+1,j),w});
    	}
    	rin(i,1,n)pre[1].poi.pb(calc_id(i,1));
    	rin(i,0,Size(shu[1])-1){
    		pre[1].sum+=shu[1][i].w;
    		pre[1].edg.pb(shu[1][i]);
    	}
    	rin(i,2,m){
    		ext.clear();
    		rin(j,1,n)pre[i].poi.pb(calc_id(j,i));
    		rin(j,0,Size(shu[i])-1){
    			pre[i].sum+=shu[i][j].w;
    			pre[i].edg.pb(shu[i][j]);
    		}
    		rin(j,0,Size(hng[i-1])-1)ext.pb(hng[i-1][j]);
    		pre[i]=merge(pre[i-1],pre[i],1);
    	}
    	rin(i,1,n)suf[m].poi.pb(calc_id(i,m));
    	rin(i,0,Size(shu[m])-1){
    		suf[m].sum+=shu[m][i].w;
    		suf[m].edg.pb(shu[m][i]);
    	}
    	irin(i,m-1,1){
    		ext.clear();
    		rin(j,1,n)suf[i].poi.pb(calc_id(j,i));
    		rin(j,0,Size(shu[i])-1){
    			suf[i].sum+=shu[i][j].w;
    			suf[i].edg.pb(shu[i][j]);
    		}
    		rin(j,0,Size(hng[i])-1)ext.pb(hng[i][j]);
    		suf[i]=merge(suf[i],suf[i+1],m);
    	}
    	ext.clear();
    	rin(i,0,Size(hng[m])-1)ext.pb(hng[m][i]);
    	q=read();
    	while(q--){
    		int l=read(),r=read();
    		printf("%lld
    ",merge(pre[l-1],suf[r+1],1).sum);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JS和jQuery获取节点的兄弟,父级,子级元素
    HTTP协议详解
    HTML5自定义属性对象Dataset
    当你输入一个网址后都发生什么
    javascript实现ajax
    第一次项目总结
    CSS简单布局总结
    animate.css总结
    自定义动画
    CSS 第四天 多重背景 变形 过渡
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10833492.html
Copyright © 2011-2022 走看看