【agc004F】Namori
Solution
好神仙的转化qwq
首先我们可以先考虑\(m=n-1\)的情况下,也就是树的情况下要怎么做
我们可以将这个问题转化一下:我们对这颗树重新染色,深度为奇数的点为黑色,深度为偶数的点为白色,这样一来原来的操作就变成了对两个相邻的颜色不同的节点进行颜色对调操作,最后的目的是要将所有的黑色点变成白色点,白色点变成黑色点
而每一次操作其实相当于交换两个点的颜色,所以我们可以得到结论:有解当且仅当白色点的数量和黑色点的数量相同
接下来为了更加直观,我们可以将这个过程理解成每次对调两个相邻的不同颜色的点的位置,使得用最少的步数做到将白点移到原来的黑点位置,黑点移到原来的白点位置
接下来我们从每条边的贡献来考虑:这条边连接的两个点需要被交换,说明原来子树中的一些点要被换出去,也就是说原来子树中的黑点比白点多或者白点比黑点多,而为了达到目的至少需要交换的次数应该是黑点和白点数量的差值
然后为什么一定能够构造出一个这样的方案的话。。我不太会严谨证明只能感性理解qwq就是考虑每一次交换都会让差值减小\(1\),最后减到\(0\)就达到目的了
所以树的情况我们就直接求出每条边两个端点中较深的那个的子树内黑点和白点的差值的绝对值,然后累加起来就是答案了
接下来就是环的情况
比较套路的处理方式是:既然我们已经知道树怎么做了,那我们考虑断掉一条边然后按照树的方法来算最后再将这条边的影响算上去
因为黑色和白色跟深度有关,所以环这里需要根据奇偶性分两类讨论
首先是奇环的情况
因为是奇环,所以环中会出现两个同色的点相邻的情况,并且我们可以选择这两个颜色相同的点进行颜色反转操作,这对我们原来统计的影响是我们可以通过这条边将其中一个颜色的点数\(+1\)另一个颜色的点数\(-1\),也就是差值\(+2\)或者\(-2\),其他的情况都和树一致,也就是说差值不一定非零就无解,只要差值是一个偶数,我们就可以通过选择这条边进行操作最终将差值变成\(0\),然后我们断掉这条边,其他的按照树来处理就好了
然后是偶环
偶环的影响会更加复杂一点,与奇环不同,在偶环上操作并不会改变黑点总数或者白点总数,所以可以单纯地理解成将点移来移去,假设我们断掉的边是\((x,y)\),我们假设在最优方案下,这条边的使用次数是\(w\)(也就是将\(x\)子树中的\(w\)个点移到\(y\)子树内,\(w\)为负数表示从\(y\)移到\(x\)),那么也就是说,断掉\((x,y)\)之后的树中,记录\(x\)子树内的那条边的答案按照树的情况处理出来为\(w1\),那么实际上这条边的贡献应该是\(w1-w\),因为有\(w\)次需要分给\((x,y)\)这条边,而对于\(y\)这个点来说,对应的边贡献则是要\(+w\),因为从\(x\)那边多了\(w\)次转移到了\(y\)的子树中
但是现在的问题是,我们并不知道\(w\)是多少,这个时候我们将答案的表达式写出来可以得到:
\]
其中\(f[e]\)表示的是按照树的方式算的每条边的贡献,\(a\)是一个系数,\(a\in \{-1,0,1\}\)
然后发现后面的形式可以看成在数轴上面给定若干个点,要确定一个点(也就是\(w\))使得所有的给定点到该点的距离之和最短,这个问题比较经典,答案应该是中位数
所以我们就可以直接将\(w\)求出来,然后计算\(ans\)啦
最后是一些实现上的问题:
1、虽然说上面的表达式中\(f\)是按照边存的,但是实际上在实现的时候按照点存会更加方便一点,\(f[i]\)表示的是\(i\)在树中从祖先过来的那条边的贡献
2、因为\(f[i]\)记录的子树内的信息,更新的时候是从后继的\(f\)值累加得到的,所以环情况中的影响需要沿着树中的祖先一路更新上去
代码大概长这个样子
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct xxx{
int y,nxt,x;
}a[N*2];
int h[N],dep[N],f[N],vis[N],pre[N],mark[N];
int rec[N],lis[N];
int n,m,tot,cutx,cuty,type,cut;
int ans;
int Abs(int x){return x<0?-x:x;}
void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].x=x;}
void predfs(int fa,int x,int d){
int u;
dep[x]=d; f[x]=d%2==0?-1:1; pre[x]=fa;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (u==fa) continue;
if (dep[u]){
cutx=x; cuty=u; cut=i;
type=((dep[x]+dep[u])%2)^1;
continue;
}
predfs(x,u,d+1);
f[x]+=f[u];
}
}
void solve(){
int tmp;
if (m==n-1){
if (f[1]){ans=-1; return;}
ans=0;
for (int i=1;i<=n;++i) ans+=Abs(f[i]);
return;
}
if (type){
if (f[1]%2){ans=-1; return;}
tmp=f[1]/2;
ans=Abs(tmp);
for (int i=cutx;i;i=pre[i]) f[i]-=tmp;
for (int i=cuty;i;i=pre[i]) f[i]-=tmp;
for (int i=1;i<=n;++i) ans+=Abs(f[i]);
return;
}
else{
if (f[1]){ans=-1; return;}
rec[0]=0;
memset(mark,0,sizeof(mark));
for (int i=cuty;i!=cutx&&i;i=pre[i])
rec[++rec[0]]=f[i],mark[i]=true;
sort(rec+1,rec+1+rec[0]);
if (rec[0]%2==0)
tmp=(rec[rec[0]/2]+rec[(rec[0]+1)/2])/2;
else
tmp=rec[(rec[0]+1)/2];
ans=Abs(tmp);
for (int i=1;i<=n;++i)
if (mark[i]) ans+=Abs(f[i]-tmp);
else ans+=Abs(f[i]);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y,tmp;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
tot=0;
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
type=1;
predfs(0,1,1);
solve();
printf("%d\n",ans);
}
【agc004F】Namori的更多相关文章
- 【agc004f】Namori Grundy
那个问一下有人可以解释以下这个做法嘛,看不太懂QwQ~ Description 有一个n个点n条边的有向图,点的编号为从1到n. 给出一个数组p,表明有(p1,1),(p2,2),…,(pn,n)这n ...
- 【ARC079F】Namori Grundy
Description 题目链接 大意:给一张基环外向树.要求给每一个点确定一个值,其值为所有后继点的\(\text{mex}\).求是否存在确定权值方案. Solution 首先,对于叶子节点,其权 ...
- 【atcoder F - Namori】**
F- Namori http://agc004.contest.atcoder.jp/tasks/agc004_f Time limit : 2sec / Memory limit : 256MB S ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
随机推荐
- dbtool一bug跟踪记
注:这篇日志是好多年前,我还在从兴公司时写的.现在都从从兴公司离职很久了,从兴也没落了,可惜.看了一下,虽然出现了部分代码,但不至于泄漏什么机密,查bug过程的原理也有可以让新手借鉴的地方,就原文照搬 ...
- Django-建立网页
进入cmd模式做 django-admin startproject helloworld创建一个project,并命名helloworld,新生成的文件结构如下 输入python manage. ...
- Jmeter接口测试之Get请求
[一] 在测试计划下面添加一个线程组---------->在线程组下面分别添加HTTP请求.响应断言.BeanShellPreProcessor.察看结果树.聚合报告等内容. [二] 将使用的协 ...
- linux 下 mysql安装和配置
最近在学习R语言,看到R与数据库交互这一部分,就自己动手实践了一下,数据库选择的是mysql,主要记录下linux下怎么安装mysql. 网上的很多资料都有相关的文章,这里只是记录下自己安装过程中遇到 ...
- 感谢——Thunder团队
团队软件的开发,已经进入第二个阶段——Beta版本了.回头看看,我们走过了很长的一段路,也经历了很多,有意见不一的争吵.有取得暂时成功时的欢欣鼓舞,我们就像一家人,就像那首歌中唱到的,“我们是一家人, ...
- DCOM初步窥探二
1.COM进程透明性表现在“组件对象和客户程序可以拥有各自的空间,也可以共享同一个进程空间”. COM负责把客户的调用正确传到组件对象中,并保证参数传递的正确性. 组件对象和客户代码不必考虑调用传递的 ...
- Beta结束感想
我得到的: 管理一个9人团队的经验 与组内成员(大部分一开始并不认识)共同向同一个目标努力的宝贵经历 学会使用Github的organization来管理整个团队的代码 学会使用leangoo这样的协 ...
- View 渲染
在Spring MVC 中,controllers不负责具体的页面渲染,仅仅是调用业务逻辑并返回model数据给view层,至于view层具体怎么展现,由专门的view层具体负责,这就是MVC模式,业 ...
- huawei oceanstor
华为产品:OceanStor 6000 V3系列 OceanStor 6800 V3 网页登入设备页面:https+ip+端口 资源分配界面: 首页: wwn为2100xxxxxxxx47e4,设 ...
- 敏捷冲刺DAY6
一. 每日会议 1. 照片 2. 昨日完成工作 3. 今日完成工作 4. 工作中遇到的困难 对于可视控件,是能进行设计的,但是对于不可视组件,比如AdoConnection怎么才能设计.但是我看del ...