【BZOJ】P4238 电压
时间:2019-09-06
本文章向大家介绍【BZOJ】P4238 电压,主要包括【BZOJ】P4238 电压使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
生成树
显然,如果是一棵树的话,那么任意拿一条边都是没关系的。
因此,我们先在图上随便生成一棵树,由于这是无向图,因此非树边只有返祖边。
那么,我们考虑非树边形成的环的奇偶性(即环上点数量的奇偶性)。
1.对于奇环:
不难发现,奇环上我们必须选一条边。换言之,我们选的边必须在奇环上。
2.对于偶环:
也不难发现,偶环上是不能选边的。
那么,本题就有大致思路了:
1.先构建一棵树
2.判断非树边构成的环的奇偶性,如果是奇环,利用树上差分把非树边两端在树上的路径上的边都+1;否则都-1,同时统计奇环数量cnt
3.遍历整棵树,判断一条边被加过的次数是否为cnt,若符合,则将ans++
注意:如果只有一个奇环,那么那条形成奇环的非树边也是可以选的,因此要将ans++
代码:
#include<bits/stdc++.h>
#define MAXN 200010
using namespace std;
int n,m,tot,head[MAXN],ST[MAXN],ED[MAXN],deep[MAXN],pre[MAXN][20],lg[MAXN],cnt[MAXN],sum,ans;
bool vis[MAXN],edge[MAXN*2],mark[MAXN];
struct node {
int ed,id,last;
} G[MAXN*4];
void Add(int st,int ed,int id) {
tot++;
G[tot]=node {ed,id,head[st]};
head[st]=tot;
}
vector<int> Tr[MAXN];
void DFS(int x,int fa) {
deep[x]=deep[fa]+1;
pre[x][0]=fa;
for(int i=1;(1<<i)<=deep[x];i++)pre[x][i]=pre[pre[x][i-1]][i-1];
vis[x]=true;
for(int i=head[x]; ~i; i=G[i].last) {
int t=G[i].ed;
if(t==fa)continue;
if(vis[t])continue;
Tr[x].push_back(t);
Tr[t].push_back(x);
edge[G[i].id]=true;
DFS(t,x);
}
}
int LCA(int x,int y){
if(deep[x]<deep[y])swap(x,y);
while(deep[x]>deep[y])x=pre[x][lg[deep[x]-deep[y]]-1];
if(x==y)return x;
for(int i=lg[deep[x]]-1;i>=0;i--){
if(pre[x][i]==pre[y][i])continue;
x=pre[x][i],y=pre[y][i];
}
return pre[x][0];
}
void solve(int x,int fa){
vis[x]=true;
for(int i=0;i<Tr[x].size();i++){
int t=Tr[x][i];
if(t==fa)continue;
solve(t,x);
cnt[x]+=cnt[t];
}
}
int main() {
for(int i=1;i<=MAXN-10;i++)lg[i]=lg[i-1]+((1<<lg[i-1])==i);
memset(head,-1,sizeof(head));
scanf("%d %d",&n,&m);
for(int i=1; i<=m; i++) {
int x,y;
scanf("%d %d",&x,&y);
Add(x,y,i);
Add(y,x,i);
}
tot=0;
for(int i=1;i<=n;i++){
if(vis[i])continue;
DFS(i,0);
}
for(int i=1;i<=n;i++){
for(int j=head[i];~j;j=G[j].last){
int t=G[j].ed,id=G[j].id;
if(edge[id])continue;
int st=i,ed=t;
if(deep[st]<deep[ed])swap(st,ed);
ST[++tot]=st,ED[tot]=ed,edge[id]=true;
}
}
for(int i=1;i<=tot;i++){
int st=ST[i],ed=ED[i],lca=LCA(st,ed);
if((deep[st]+deep[ed]-2*deep[lca]+1)%2==0)cnt[st]--,cnt[ed]--,cnt[lca]+=2;
else cnt[st]++,cnt[ed]++,cnt[lca]-=2,sum++;
}
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++){
if(vis[i])continue;
mark[i]=true;
solve(i,0);
}
for(int i=1;i<=n;i++){
if(mark[i])continue;
if(cnt[i]==sum)ans++;
}
if(sum==1)ans++;
printf("%d",ans);
return 0;
}
原文地址:https://www.cnblogs.com/SillyTieT/p/11476923.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法