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;
}