noip模拟63

考试过程:这次考试四个题基本上都是计数题,我觉得不太可做,就按顺序开题。

首先是T1,瓶颈就在于找环,但是我想了半天,没什么思路,只会\(o(n)\)找环,但是这样做复杂度是\(n\times m\)的,可以获得10pts的高分,再加上一个特殊性质,最终我获得了20pts的高分

然后是T2,首先是考虑XIN队算法,但是这个暴搜和之前的不太一样,需要想一下。

冲完XIN队后我看了看后面两个题,无思路,就又回来想T2,看到特殊性质,我就想拿这一档的分,但是我理解错了,它说的是区间没有相交,我当时以为区间嵌套和相交是没有关系的,结果考完试后强者cty告诉我嵌套是包含于相交的,我谔谔。那这部分算是白打了,以后一定要理解题意。

T1 电机压制

思路:建一棵DFS树,则特殊边就全部为返祖边。
\(odd_u\)对结点\(u\)统计奇环,\(even_u\)统计偶环.设一条返祖边为 \(u -> v\)若它形成奇环,则\(odd[u]++\),\(odd[v]--\).
\(x\)的子树所有结点的\(odd\)之和,即为\(x ->fa\)这条边被多少奇环包含(利用差分前缀和的思想)
注意实现细节:
1.当只有一个奇环的时候需要特判一下最后那一条边是不是重边,如果是那就没有贡献,否则的话\(ans++\)
2.若自己的儿子对答案造成了贡献,但是自己和儿子的连边是重边,那么\(ans--\)
代码如下:

AC_code
#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define mid ((l+r)>>1)
#define lc (rt<<1)
#define rc (rt<<1|1)
#define f() cout<<"fuck"<<endl
#define head headddd
#define next net
using namespace std;
const int N=2e5+10;
unordered_map<int,bool> mp[N],no[N];
int n,m,tot,num,com,ans,fw;
int to[N<<1],head[N],next[N<<1],deep[N];
int odd[N],even[N],ji[N];
bool vis[N],flag;
ii read()
{
	int x=0;char ch=getchar();bool f=1;
	while(ch<'0' or ch>'9')
	{
		if(ch=='-') f=0;
		ch=getchar();
	}
	while(ch>='0' and ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return f?x:(-x);
}
iv add(int x,int y)
{
	to[++tot]=y;
	next[tot]=head[x];
	head[x]=tot;
}
iv dfs(int st,int f)
{
	vis[st]=1;
	deep[st]=deep[f]+1;
	for(re i=head[st];i;i=next[i])
	{	
		int p=to[i];
		if(p==f) continue;
		if(vis[p])
		{
			if(deep[p]>deep[st]) continue;
			if((deep[st]-deep[p]+1)&1) ++odd[st],--odd[p],++num;
			else ++even[st],--even[p],++com;
			continue;
		}
		dfs(p,st);
	}
}	
iv dfs2(int st,int f)
{
	vis[st]=1;
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		if(vis[p]) continue;
		dfs2(p,st);
		if(odd[p]==num and even[p]==0 and no[st][p]) --ans;
		odd[st]+=odd[p],even[st]+=even[p];
	}
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		if(vis[p] and deep[p]<deep[st] and no[st][p] and odd[st]==num and even[st]==0) flag=1;
	}
}
signed main()
{
	freopen("a.in","r",stdin),freopen("a.out","w",stdout);
	n=read(),m=read();
	int u,v;
	for(re i=1;i<=m;i++)
	{
		u=read(),v=read();
		if(mp[v].find(u)==mp[v].end()) add(u,v),add(v,u),mp[v][u]=mp[u][v]=1;	
		else
		{
			if(no[v][u]) fw++;
			else fw+=2;
			no[v][u]=no[u][v]=1;
		}
	}
	dfs(1,0);
	for(re i=1;i<=n;i++) vis[i]=0;
	dfs2(1,0);
	if(num!=0 or com!=0)
	{
		for(re i=2;i<=n;i++) if(odd[i]==num and even[i]==0) ++ans;
		if(num==1 and !flag) ans++;
	}
	else ans=m-fw;
	printf("%d\n",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/WindZR/p/15345416.html