Portal -->agc004F

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\)是多少,这个时候我们将答案的表达式写出来可以得到:

\[ans=abs(w)+\sum\limits_{e}abs(f[e]+a\cdot 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的更多相关文章

  1. 【agc004f】Namori Grundy

    那个问一下有人可以解释以下这个做法嘛,看不太懂QwQ~ Description 有一个n个点n条边的有向图,点的编号为从1到n. 给出一个数组p,表明有(p1,1),(p2,2),…,(pn,n)这n ...

  2. 【ARC079F】Namori Grundy

    Description 题目链接 大意:给一张基环外向树.要求给每一个点确定一个值,其值为所有后继点的\(\text{mex}\).求是否存在确定权值方案. Solution 首先,对于叶子节点,其权 ...

  3. 【atcoder F - Namori】**

    F- Namori http://agc004.contest.atcoder.jp/tasks/agc004_f Time limit : 2sec / Memory limit : 256MB S ...

  4. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  5. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  6. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  8. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  9. Python高手之路【三】python基础之函数

    基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...

随机推荐

  1. localhost/127.0.0.1/本机IP的区别以及端口号

    端口号: http请求默认的端口是:80 PHPstudy中的端口号: Apache服务器的端口是:80 MySQL数据库的端口是:3306 PHP项目端口是:9000 禅道中的端口号: Apache ...

  2. windows下Mongodb图形化工具安装及配置

    接上篇文章<Windows下Mongodb安装部署.docx> 一.RockMongo 1.RockMongo需要php环境,首先需要搭建php环境,选择采用 下载xampp,这里我用的是 ...

  3. HTML从入门到放弃

    一.HTML 简介 链接:https://www.cnblogs.com/baishuchao/articles/9179920.html 二.HTML 基础 链接:https://www.cnblo ...

  4. Java线程Run和Start的区别

    先上结论:run只是Thread里面的一个普通方法,start是启动线程的方法.何以见得呢?可以执行下面的代码看看run和start的区别: package com.basic.thread; /** ...

  5. 数据库sql优化总结之1-百万级数据库优化方案+案例分析

    项目背景 有三张百万级数据表 知识点表(ex_subject_point)9,316条数据 试题表(ex_question_junior)2,159,519条数据 有45个字段 知识点试题关系表(ex ...

  6. linux中匹配正确的ip地址

    1.假设IP地址是规范的,没有出错误的 sed -n "/[0-9]\{1,3\}.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/p" test ...

  7. centos7.2 apache开启.htaccess

    打开httpd.conf(在那里? APACHE目录的CONF目录里面),用文本编纂器打开后,查找 (1) AllowOverride None 改为 AllowOverride All (2)去掉下 ...

  8. pip安装Crypto注意事项

    pip install PyCrypto 1.使用pip install Crypto的方式安装的文件夹名称为crypto,而内部引用都用的Crypto路径,因此pip安装后,需要将文件夹名称修改为C ...

  9. World Cup(思维+模拟)

    Description Allen wants to enter a fan zone(球迷区) that occupies a round square and has nn entrances. ...

  10. Scrum立会报告+燃尽图 05

    此作业要求参见:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2195] 一.小组介绍 组长:王一可 组员:范靖旋,王硕,赵佳璐,范洪达 ...