• 4.18 省选模拟赛 桥 边双联通分量 长链剖分维护贪心


    avatar
    avatar

    只存在加边操作 所以每次只对割边有影响。

    考虑求出所有的边双联通分量 然后进行缩点。

    那么原图就变成了一颗树 且所有边都是割边。

    考虑k==1的时候 显然是求出树的直径。

    考虑k>1时 一个错误的贪心:把刚才树的直径上的边标记为0 然后再求直径......

    容易构造出反例让其错误。

    题解上的做法过于神仙 看不懂。

    给一种自己做CF某道题后得到的贪心思路。

    容易发现选出k条边 某种意义上来说是选出了2k个点。

    我们还可以知道这2k个点中 其中必然有两个点包含树的直径两端点。

    但是直接选出2k个点可能是不合法的。而且此时无根很难计算出来答案。

    我们知道了必然有两个点是树的直径两端点了 以其中一个点为根。

    那么剩下的就是选取2k-1个点每个点的最初权值为点到根路径上的边数。

    考虑每次选取最大的。这个贪心容易使用长链剖分进行优化 排一下序或者使用堆维护即可。

    正确性:最初根为直径某个端点显然正确,接着这2k个点包括根显然是可以两两配对组成k条边和题目吻合。

    最优性:每次权值都尽可能的大所以是最优的。(还需要斟酌一下 好多题都是这样贪的

    const int MAXN=200010;
    int n,m,Q,id,len=1,cnt,cc,len1=1,s1,s2,maxx;
    int c[MAXN],vis[MAXN],dis[MAXN];
    int dfn[MAXN],low[MAXN],mark[MAXN<<1],f[MAXN],q[MAXN],mx[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],sz[MAXN],son[MAXN],fa1[MAXN];
    int lin1[MAXN],ver1[MAXN<<1],nex1[MAXN<<1],e1[MAXN<<1];
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    inline void add1(int x,int y,int z)
    {
    	ver1[++len1]=y;
    	nex1[len1]=lin1[x];
    	lin1[x]=len1;
    	e1[len1]=z;
    }
    inline void dfs(int x,int las)
    {
    	dfn[x]=low[x]=++cnt;
    	go(x)
    	{
    		if(i==(las^1))continue;
    		if(!dfn[tn])
    		{
    			dfs(tn,i);
    			low[x]=min(low[x],low[tn]);
    			if(low[tn]>dfn[x])mark[i]=1;
    		}
    		else low[x]=min(low[x],dfn[tn]);
    	}
    }
    inline void dfs(int x)
    {
    	vis[x]=1;c[x]=id;
    	go(x)
    	{
    		if(vis[tn]||mark[i]||mark[i^1])continue;
    		dfs(tn);
    	}
    }
    inline int bfs(int w)
    {
    	maxx=0;++cc;
    	int l=0,r=0,ww=0;
    	q[++r]=w;dis[w]=0;vis[w]=cc;
    	while(++l<=r)
    	{
    		int x=q[l];
    		if(dis[x]>maxx)
    		{
    			ww=x;
    			maxx=dis[x];
    		}
    		for(int i=lin1[x];i;i=nex1[i])
    		{
    			int tn=ver1[i];
    			if(vis[tn]!=cc)
    			{
    				dis[tn]=dis[x]+e1[i];
    				vis[tn]=cc;
    				q[++r]=tn;
    			}
    		}
    	}
    	return ww;
    }
    inline int dp(int x,int fa)
    {
    	if(x==s2)return 1;
    	for(int i=lin1[x];i;i=nex1[i])
    	{
    		int tn=ver1[i];
    		if(tn==fa)continue;
    		if(dp(tn,x))
    		{
    			e1[i]=e1[i^1]=0;
    			return 1;
    		}
    	}
    	return 0;
    }
    inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
    inline void dp1(int x,int fa)
    {
    	sz[x]=sz[fa]+1;mx[x]=sz[x];
    	fa1[x]=fa;
    	for(int i=lin1[x];i;i=nex1[i])
    	{
    		int tn=ver1[i];
    		if(tn==fa)continue;
    		dp1(tn,x);
    		//cout<<mx[tn]<<' '<<mx[x]<<endl;
    		if(mx[tn]>mx[x])
    		{
    			son[x]=tn;
    			mx[x]=mx[tn];
    		}
    	//	cout<<son[x]<<endl;
    	}
    }
    priority_queue<int>s;
    inline void dp2(int x,int fa)
    {
    	if(fa==x)
    	{
    		if(x==s1)s.push(mx[x]-sz[x]);
    		else s.push(mx[x]-sz[fa1[x]]);
    		//cout<<mx[x]-sz[x]<<endl;
    		//cout<<son[x]<<' '<<x<<endl;
    	}
    	if(son[x])dp2(son[x],fa);
    	for(int i=lin1[x];i;i=nex1[i])
    	{
    		int tn=ver1[i];
    		if(tn==fa1[x]||son[x]==tn)continue;
    		dp2(tn,tn);
    		//cout<<"ww"<<endl;
    	}
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	freopen("bridge.in","r",stdin);
    	freopen("bridge.out","w",stdout);
    	get(n);get(m);get(Q);
    	rep(1,m,i)
    	{
    		int get(x);int get(y);
    		add(x,y);add(y,x);
    	}
    	dfs(1,0);cc=1;
    	rep(1,n,i)if(!vis[i])++id,dfs(i);
    	rep(1,id,i)f[i]=i;
    	rep(1,n,j)go(j)
    	{
    		if(c[j]==c[tn])continue;
    		int xx=getfather(c[j]);
    		int yy=getfather(c[tn]);
    		if(xx==yy)continue;
    		f[xx]=yy;
    		add1(c[j],c[tn],1);
    		add1(c[tn],c[j],1);
    	}
    	--id;int ans=0;
    	s1=bfs(1);s2=bfs(s1);
    	dp1(s1,0);
    	dp2(s1,s1);
    	ans+=s.top();
    	s.pop();
    	put(ans);
    	rep(2,Q,i)
    	{
    		if(s.size())
    		{
    			ans+=s.top();
    			s.pop();
    		} 
    		if(s.size())
    		{
    			ans+=s.top();
    			s.pop();
    		} 
    		put(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    查看tomcat启动文件都干点啥---server对象
    Spring的AOP浅尝
    Spark1.3.0安装
    HMM的概率计算问题和预测问题的java实现
    C语言实现求字符串子集问题
    AdaBoost的java实现
    ID3决策树预测的java实现
    决策树ID3算法的java实现
    Naive Bayes在mapreduce上的实现
    Kmeans在MapReduce中的实现
  • 原文地址:https://www.cnblogs.com/chdy/p/12770030.html
Copyright © 2020-2023  润新知