[***]HZOJ 哪一天她能重回我身边
%%%神仙题。
居然是图论,我还一直以为是二分图或者啥数据结构。
直接说正解了,将数看作节点,牌看做边,从牌的正面的数想反面连边权为1的边,反面向正面连边权为0的边(注意用到成对存储的技巧,之后会非常巧妙地用到),可以发现就是要求反转几条边可以使每个点的出读小于等于1。那么每个联通图只可能是树或基环树。可以先dfs判断求出每个联通图的点数np和边数ne,若ne/2(双向边)>np,那么这个联通图不合法直接输出-1 -1即可。
void dfs(int x,int fa)
{
vi[x]=;np++;
for(int i=f(x);i;i=n(i))
{
ne++;
if(v(i)!=fa)
if(!vi[v(i)])dfs(v(i),x);
}
}
bool pd()
{
for(int i=;i<=n*;i++)
if(!vi[i])
{
np=ne=,dfs(i,);
if(np<ne/)return ;
}
return ;
}
代码实现
接下来考虑他是树的情况:
对于确定的跟节点,翻转的边的个数就是将所有点指向父亲节点(可以动手画一下),可以用树形dp求得。但是要枚举根节点吗?其实可以用到二次扫描和换根法,设以x为根要反转的边数为f[x],那么其实f[son]可以用f[x]更新:如果x->son的边权为1,则f[son]=f[x]-1,否则f[son]=f[x]+1.这样我们就解决了树的情况。
int f[MAXN],st,en,ned;
void dfs1(int x,int fa)
{
v[x]=;f[x]=;
for(int i=f(x);i;i=n(i))
if(v(i)!=fa)
{
if(!v[v(i)])
{
dfs1(v(i),x);
f[x]+=f[v(i)]+w(i);
}
else st=u(i),en=v(i),ned=i;
}
}
int f2[MAXN];
vector<int> tem;
void dfs2(int x,int fa)
{
tem.push_back(f2[x]);
for(int i=f(x);i;i=n(i))
if(v(i)!=fa && i!=ned && i!=(ned^))
{
if(w(i))f2[v(i)]=f2[x]-;
else f2[v(i)]=f2[x]+;
dfs2(v(i),x);
}
}
代码实现
下面看基环树:
在dfs时找出环上的随机一条边记录,将它去掉按树处理,最后在考虑这条边的影响。那么边的成对储存就有用了,将边的编号%2就是它从u指向v的权值。
ned%=;
if(f2[st]+ned==f2[en]+(ned^))minn=;
else minn=;
ans+=min(f2[st]+ned,f2[en]+(ned^));
代码实现
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define MAXN 200010
#define mod 998244353
#define LL long long
#define int LL
#define ma(x) memset(x,0,sizeof(x))
using namespace std;
struct edge
{
int u,v,w,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define w(x) ed[x].w
#define n(x) ed[x].nxt
}ed[MAXN*];
int first[MAXN],num_e=;
#define f(x) first[x]
int T,n; int np,ne;
bool v[MAXN],vi[MAXN];
void dfs(int x,int fa)
{
vi[x]=;np++;
for(int i=f(x);i;i=n(i))
{
ne++;
if(v(i)!=fa)
if(!vi[v(i)])dfs(v(i),x);
}
}
bool pd()
{
for(int i=;i<=n*;i++)
if(!vi[i])
{
np=ne=,dfs(i,);
if(np<ne/)return ;
}
return ;
}
int f[MAXN],st,en,ned;
void dfs1(int x,int fa)
{
v[x]=;f[x]=;
for(int i=f(x);i;i=n(i))
if(v(i)!=fa)
{
if(!v[v(i)])
{
dfs1(v(i),x);
f[x]+=f[v(i)]+w(i);
}
else st=u(i),en=v(i),ned=i;
}
}
int f2[MAXN];
vector<int> tem;
void dfs2(int x,int fa)
{
// v[x]=1;
tem.push_back(f2[x]);
for(int i=f(x);i;i=n(i))
if(v(i)!=fa && i!=ned && i!=(ned^))
{
if(w(i))f2[v(i)]=f2[x]-;
else f2[v(i)]=f2[x]+;
// if(!v[v(i)])
dfs2(v(i),x);
}
}
inline void add(int u,int v,int w);
signed main()
{
// freopen("back5.in","r",stdin);
// freopen("1.out","w",stdout); cin>>T;
while(T--)
{
ma(f);ma(f2);ma(v);ma(vi);ma(first);num_e=;tem.clear();
scanf("%lld",&n);
int a,b;
for(int i=;i<=n;i++)
{
scanf("%lld%lld",&a,&b);
add(a,b,);add(b,a,);
}
if(pd()){puts("-1 -1");continue;}
int minn=,ans=,ans2=;
for(int i=;i<=n*;i++)
if(!v[i])
{
st=en=ned=-;tem.clear();minn=;
dfs1(i,);
f2[i]=f[i];
dfs2(i,);
if(st==-)
{
sort(tem.begin(),tem.end());
for(int j=;j<tem.size();j++)
if(tem[j]==tem[])minn++;
else break;
ans+=tem[];
}
else
{
ned%=;
if(f2[st]+ned==f2[en]+(ned^))minn=;
else minn=;
ans+=min(f2[st]+ned,f2[en]+(ned^));
}
ans2=(ans2*minn)%mod;
}
printf("%lld %lld\n",ans,ans2);
}
}
inline void add(int u,int v,int w)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
w(num_e)=w;
n(num_e)=f(u);
f(u)=num_e;
}
完整代码
[***]HZOJ 哪一天她能重回我身边的更多相关文章
- Noip模拟77 2021.10.15
T1 最大或 $T1$因为没有开$1ll$右移给炸掉了,调了一年不知道为啥,最后实在不懂了 换成$pow$就过掉了,但是考场上这题耽误了太多时间,后面的题也就没办法好好打了.... 以后一定要注意右移 ...
- $dy$讲课总结
字符串: 1.广义后缀自动机(大小为\(m\))上跑一个长度为\(n\)的串,所有匹配位置及在\(parent\)树上其祖先的数量的和为\(min(n^2,m)\),单次最劣是\(O(m)\). 但是 ...
- 重回博客 谈一谈Node中的异步和单线程
重回博客,这个帐号之前注册后就只发了一篇博客.听朋友建议,决定一周两次更新. 第一篇谈论一下最近想的比较多的异步的问题. 传统多线程异步 传统的异步是多线程的,当要同时做两件事的时候,他们是执行在不同 ...
- Python之父重回决策层
在Guido van Rossum(吉多·范罗苏姆)卸任BDFL(“终身仁慈独裁者”)一职半年多之后,Python社区迎来了新的治理新方案:指导委员会模式,而经过投票Guido van Rossum也 ...
- Python之父重回决策层,社区未来如何发展?
春节假期结束了,大家陆续地重回到原来的生活轨道上.假期是一个很好的休息与调节的机会,同时,春节还有辞旧迎新的本意,它是新的轮回的开端. 在 Python 社区里,刚发生了一件大事,同样有开启新纪元的意 ...
- 《重回耶路撒冷——犹太人的三千年》(Return to Jerusalem)读后感
写在前面 书名:<重回耶路撒冷——犹太人的三千年>(Return to Jerusalem) 作者:张力升 来源:长清图书馆 阅读用时:其实年前拿到书,本来想寒假在家看的,但是在家一点儿都 ...
- Rabbitmq——实现消费端限流 --NACK重回队列
如果是高并发下,rabbitmq服务器上收到成千上万条消息,那么当打开消费端时,这些消息必定喷涌而来,导致消费端消费不过来甚至挂掉都有可能. 在非自动确认的模式下,可以采用限流模式,rabbitmq ...
- 两年,VMware又重回巅峰?
两年前,被公有云和容器打的焦头烂额的VMware一度被众多业界人士看衰,营收.股价双双下滑.然而,仅仅经过短短两年时间,VMware已经和AWS,IBM.微软.Rackspace等众多公有云厂商成为合 ...
- 纳德拉再造微软:市值如何重回第一阵营(思维确实变了,不再是以windows为中心,拥抱其它各种平台,敢在主战场之外找到适合自己的新战场)
有人说,现在的美国硅谷充满了“咖喱味”.也有人说,硅谷已经变成“印度谷”.原因就在于,以微软CEO萨提亚·纳德拉.谷歌CEO桑达尔·皮查伊为代表的印度人,近年以来掌控了全世界最令人望而生畏的科技巨头. ...
随机推荐
- drf的序列化器
三流 import sys #标准输出流 sys.stdout.write('123\n') sys.stdout.write('456\n') #标准输入流 res=sys.stdin.readli ...
- 关闭防火墙,仍然无法访问80端口 centos
如果你用的是阿里云,那么需要添加80端口开放才行,在云服务器-安全组-添加安全组
- Django基础内容整理
- SQL Server 存储过程详解
转自:https://blog.csdn.net/younghaiqing/article/details/62884658 一. 什么是存储过程 系统存储过程是系统创建的存储过程,目的在于能够方便的 ...
- GDOI2017第四轮day1总结
总的来说这场比赛,只能说是勉强正常发挥. 实在是知识水平有限,最后没能突破瓶颈. 有几个做得好的地方: 1.想好了在写题: 2.暴力也会拍 3.适当地放弃题. 要学习的东西: 1.Sg,线性基: 2. ...
- 批量删除maven lastUpdated
批量删除lastUpdated for /r %i in (*.lastUpdated) do del %i 安装jar到本地仓库 mvn install:install-file -Dfile=D: ...
- elipse egit的使用
- PYTHON网络爬虫与信息提取[scrapy框架应用](单元十、十一)
scrapy 常用命令 startproject 创建一个新的工程 scrapy startproject <name>[dir] genspider 创建一个爬虫 ...
- 为什么要用Spring的依赖注入
最近写了一些Spring项目,用到了依赖注入,但是不知道为甚么要用,后来在知乎上看了一些大家的回答,觉得很精辟,遂简单总结一下. 主要是实现类之间的解耦,假如A类依赖B类,在实例化A类的话也要new一 ...
- Spring_通过Bean的Factory配置Bean
package com.tanlei.bean.FactoryBean; import org.springframework.beans.factory.FactoryBean; public cl ...