首页 > 其他分享 >【洛谷P7816 】【Stoi2032】以父之名

【洛谷P7816 】【Stoi2032】以父之名

时间:2022-10-31 08:33:41浏览次数:59  
标签:度数 cnt 洛谷 val vis int 以父之名 边权 P7816

在洛谷题解中看到了两种做法。

法一:

与zjr巨佬说的类似,我们先能观察出这个图的几个性质:

  • 若只保留边权为 \(1\) 的边,那么所有点的度数都是奇数。那么也可以得到 \(n\) 为偶数。
  • 若只保留边权为 \(2\) 的边,这个图没有规律,即每个点的度数可以是奇数也可以是偶数。
  • 原图中度数为奇数的点有偶数个。(你可以考虑一条边会贡献两个度数,所以总度数应该是偶数)

考虑构造欧拉回路来解决问题:我们建立一个虚点与所有度数为奇数的点连一条边权为 \(1\) 的边,这样保证了原图中的所有点和虚点的度数都是偶数,然后跑欧拉回路。

跑欧拉回路时,假设从边权为 \(w\) 的边进入点 \(u\),那么我们优先选择边权也为 \(w\) 的边。

为什么这么跑?我们可以按不同类型的点分类讨论:

  • 若点 \(u\) 有奇数条边权为 \(2\) 的边,那么 \(u\) 有奇数条边权为 \(1\) 的边,最后跑出来剩下肯定是 \(2\) 和 \(1\) 搭配,差为 \(1\)。
  • 若点 \(u\) 有偶数条边权为 \(2\) 的边,那么 \(u\) 有偶数条边权为 \(1\) 的边(其中一条连向虚点),那么最后跑出来肯定有一条原图的 \(1\) 边与连向虚点的 \(1\) 边搭配,对应到原图上差也为 \(1\)。

这种方法思路巧妙,实现简单,但是是在我写完第二种方法代码时才看到的。

法二:

我们先把图分为两部分:只保留边权为 \(1\) 的图 \(G_1\),只保留边权为 \(2\) 的图 \(G_2\)。

我们对图 \(G_1\)、\(G_2\) 都分别删环。因为对于环(边权都为相同)我们可以直接将所有的边按同一个方向定向而不会有影响。于是图 \(G_1\)、\(G_2\) 都变成了树。

我们对图 \(G_1\)、\(G_2\) (此时它们都是树)都分别剖链。使得:对于 \(G_1\),每个点恰好为一条链的端点,对于 \(G_2\),每个点至多为一条链的端点。然后我们让一条链上的边都按同一个方向定向,于是一条链就可以看成这条链两个端点之间的一条边。那么把 \(G_1\) 和 \(G_2\) 拼起来就转化为了性质 B 的 subtask。

最后我们按性质 B 的 subtask 的方法来实现链的定向即可。

码量有一点大,但不是很复杂。

#include<bits/stdc++.h>

#define N 1000010
#define M 3000010

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct Graph
{
	int cnt,head[N],cur[N],nxt[M<<1],to[M<<1],id[M<<1];
	Graph(){cnt=1;}
	void adde(int u,int v,int idd)
	{
		to[++cnt]=v;
		id[cnt]=idd;
		nxt[cnt]=head[u];
		head[u]=cnt;
	}
}g1[2],g2[2],G;

int n,m;
int lca[N<<1],w[N<<1];
int fa[2][N],tofa[2][N];
int direc[M];
Graph *g,*gg;

bool ins[N];
int st,del[M<<1];

bool dfs1(int u,int from)
{
	if(ins[u])
	{
		st=u;
		return true;
	}
	ins[u]=1;
	for(int &i=(*g).head[u];i;i=(*g).nxt[i])
	{
		int v=(*g).to[i];
		if(i==(from^1)||del[i]!=-1) continue;
		if(dfs1(v,i))
		{
			del[i]=del[i^1]=1;
			direc[abs((*g).id[i])]=((*g).id[i]<0);
			if(u!=st)
			{
				ins[u]=0;
				return true;
			}
		}
		else del[i]=del[i^1]=0;
	}
	ins[u]=0;
	return false;
}

void delring(Graph &g1,Graph &g2)
{
	g=&g1,gg=&g2;
	memset(ins,0,sizeof(ins));
	memset(del,-1,sizeof(del));
	for(int i=1;i<=n;i++) 
		dfs1(i,-1);
	for(int i=2;i<=(*g).cnt;i+=2)
	{
		if(!del[i])
		{
			(*gg).adde((*g).to[i^1],(*g).to[i],(*g).id[i]);
			(*gg).adde((*g).to[i],(*g).to[i^1],(*g).id[i^1]);
		}
	}
}

int rt,val;
bool vis[N];

int dfs2(int u)//0 son->fa 1 fa->son
{
	vis[u]=1;
	int a,b;
	bool tag=0;
	for(int i=(*g).head[u];i;i=(*g).nxt[i],tag^=1)
	{
		int v=(*g).to[i];
		if(vis[v])
		{
			tag^=1;
			continue;
		}
		tofa[val-1][v]=(*g).id[i^1];
		fa[val-1][v]=u;
		if(!tag) a=dfs2(v);
		else
		{
			b=dfs2(v);
			G.adde(a,b,114514);
			w[G.cnt]=val;
			lca[G.cnt]=u;
			G.adde(b,a,114514);
			w[G.cnt]=val;
			lca[G.cnt]=u;
		}
	}
	if(tag)
	{
		if(u==rt)
		{
			b=rt;
			G.adde(a,b,114514);
			w[G.cnt]=val;
			lca[G.cnt]=u;
			G.adde(b,a,114514);
			w[G.cnt]=val;
			lca[G.cnt]=u;
		}
		return a;
	}
	return u;
}

void divide(Graph &ng,int nv)
{
	g=&ng,val=nv;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			rt=i;
			dfs2(i);
		}
	}
}

void make_direc(int i,int v)
{
	int a=G.to[i^1],b=G.to[i],f=lca[i];
	while(a!=f)
	{
		direc[abs(tofa[v-1][a])]=(tofa[v-1][a]<0);
		a=fa[v-1][a];
	}
	while(b!=f)
	{
		direc[abs(tofa[v-1][b])]=(tofa[v-1][b]>0);
		b=fa[v-1][b];
	}
}

void dfs3(int u,int from)
{
	vis[u]=1;
	for(int i=G.head[u];i;i=G.nxt[i])
	{
		int v=G.to[i];
		if(i==(from^1)) continue;
		make_direc(i,w[i]);
		if(vis[v]) continue;
		dfs3(v,i);
		return;
	}
}

int d[N];

void work()
{
	for(int i=2;i<=G.cnt;i+=2)
		d[G.to[i]]++,d[G.to[i^1]]++;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
		if(d[i]==1&&!vis[i]) dfs3(i,-1);
	for(int i=1;i<=n;i++)
		if(!vis[i]) dfs3(i,-1);
}

int main()
{
//	freopen("trial_sample4.in","r",stdin);
//	freopen("trial_sample4.out","w",stdout);
	memset(direc,-1,sizeof(direc));
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read(),w=read();
		if(u==v) continue;
		if(w==1) g1[0].adde(u,v,i),g1[0].adde(v,u,-i);
		else g2[0].adde(u,v,i),g2[0].adde(v,u,-i);
	}
	delring(g1[0],g1[1]);
	delring(g2[0],g2[1]);
	divide(g1[1],1);
	divide(g2[1],2);
	work();
	for(int i=1;i<=m;i++)
		putchar(direc[i]?'1':'0');
	return 0;
} 

标签:度数,cnt,洛谷,val,vis,int,以父之名,边权,P7816
From: https://www.cnblogs.com/ez-lcw/p/16843017.html

相关文章

  • 洛谷 P1153 点和线
    前置知识(1)求两条线段的交点方法1,运用高中的解析几何知识求.方法2,运用向量点积求.考虑向量叉乘。若\(\veca\times\vecb>0\),那么\(\vecb\)在\(\veca\)......
  • 洛谷 P1789【Mc生存】插火把
    萌新写的代码,长但模块化#include<stdio.h>#defineROW100#defineCOLUMN100intmap[ROW][COLUMN];/*函数测试数据={1,1,1,0,0,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0......
  • 洛谷P8539 「Wdoi-2」来自地上的支援 题解
    ST表做法思路当进行第\(x\)次操作时,若\(b_1\)到\(b_{x-1}\)中有比\(b_x\)大的数,那这次操作轮不到\(b_x\),并且前面的本来就比它大的数只会越来越大,所以以后的......
  • P1597洛谷刷题
    #include<iostream>#include<string>usingnamespacestd;intmain(intargc,char**argv){ stringstr="a:=3;b:=4;c:=5"; for(inti=1;i<=3;i++){ ints......
  • 洛谷P5759题解
    本文摘自本人洛谷博客,原文章地址:https://www.luogu.com.cn/blog/cjtb666anran/solution-p5759\[这道题重在理解题意\]选手编号依次为:\(1,2...N\)(\(N\)为参赛总人数)。......
  • 【EA的练习赛2】【洛谷P7274】草地(单调栈,LCT维护最小生成树)
    学到了很多。我们分步走。首先在做这道题前先观察到几个小性质:操作顺序不同不影响结果发现对于每一个黑点,一通操作过后它扩展出的区域是一个矩形,而操作顺序是不影响......
  • 洛谷P3391 【模板】文艺平衡树
    题目描述您需要写一种数据结构(可参考题目标题),来维护一个有序数列。其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4] 的话,结果是5 2 ......
  • 洛谷P8805题解
    原题P8805[蓝桥杯2022国B]机房思路概述题意分析给定一个\(n\)个点的无根树,每个点的权值等于其出边数量。对于给定的\(m\)组询问,第\(i(1≤i≤n)\)组询问包......
  • 洛谷 P6294
    首先有一个显而易见的性质:每次取都是取最大的一个数。然后就变成了加数,取最大值,加数,取最大值。。。直接单走一个优先队列(但是很明显这个数据不打算把优先队列放过去。......
  • 洛谷 P1077 [NOIP2012 普及组] 摆花 (DP)
    https://www.luogu.com.cn/problem/P1077题目描述摆上m盆花。一共有n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同......