洛谷题目传送门

神仙思维题还是要写点东西才好。

每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移。

因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一枚棋子,每次可以将棋子移向相邻的空位,目标状态是树的偶数层的所有点上都有棋子。

这样的互换总次数有没有一个下界呢?

我们求出\(a_i\)表示点\(i\)子树中棋子数量与空位数量之差(可以是负数),那么\(i\)的父边就至少要交换\(|a_i|\)次。

为什么呢?子树里面空位比棋子少的话,肯定要通过父边把\(a_i\)个棋子送出去,才能移进来\(a_i\)个空位。反之亦然。

于是,如果\(a_{rt}\)(根)不为\(0\)就无解,否则\(\sum\limits_{i=1}^n|a_i|\)就是答案下界。

然后,仔细推一下发现它就是答案。

对于一个点,它的父边和所有子边的移进移出的顺序,和其它点的顺序是互相独立的。

等于说我们总能安排一个合法的顺序,使得它们一进一出一进一出。。。这样完整地衔接起来,而不会互相矛盾。

基环树

环长为偶数

显然的想法:把整个环当做根,不在环上的点的答案照算不误。所以把多出来一条边去掉做好树形DP。

首先这还是一个二分图,因此\(a_{rt}\)不为\(0\)同样无解。

于是,似乎这条边存在的意义只有分摊一部分转移、减少总次数了。

那么接下来要做的是,确定环上每条边的移动方向和次数。

设环长为\(n\),\(A_i\)为以\(i\)为根求得的\(a\)值,\(x_i\)为环上第\(i\)条边的移动参数(正负表示方向,绝对值表示次数)

因为进出平衡,我们可以得到一个方程组

\[\begin{cases}x_1-x_2=A_1\\x_2-x_3=A_2\\...\\x_n-x_1=A_n\end{cases}
\]

这时候我们发现上面那个方程组是没有唯一解的。那到底该分摊多少呢?

不着急,我们着眼于最小化\(\sum|x_i|\),再把方程组整一整

\[\begin{cases}x_1=x_1-0\\x_2=x_1-A_1\\x_3=x_1-A_1-A_2\\...\\x_n=x_1-\sum_{i=1}^{n-1}A_i\end{cases}
\]

每一行的\(A\)都是前缀和的形式,在树形DP的时候对应的是环上的每个点的\(a\)。

看到这儿就豁然开朗了。这不等于说,数轴上有若干个点取值分别为每一个\(a\),找到一个点\(x_1\)使它到所有点距离之和最小?

把所有\(a\)排序,\(x_1\)不就可以取第\(\frac n 2\)大的数到第\(\frac n 2+1\)大的数之间的任意整数么?

最后把环上的DP值改一改就OK了。

环长为奇数

因为不是二分图了,所以直接解方程好像做不下去。我们从更直观的意义来理解它。

仍然是去掉一条边做树形DP。这时候我们看看,在这条非树边上操作,在奇偶染色模型下等价于什么呢?

没错,两个棋子会在这里同时变成空位,两个空位会在这里同时变成棋子!

那这条边存在的意义,是把棋子或空位中多的减掉、少的补上。要操作多少次呢?\(\frac{\sum A_i}{2}\),在树形DP中对应的是\(\frac{a_{rt}}{2}\)。

注意如果\(a_{rt}\)是奇数那么无解。否则环底部的\(A\)发生了变化,导致要把环上的\(a\)都减掉\(\frac{a_{rt}}{2}\)。


最后的最后扫一遍数组统计答案。代码没有任何难点。

  1. #include<bits/stdc++.h>
  2. #define R register int
  3. #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
  4. using namespace std;
  5. const int SZ=1<<19,N=1e5+9,M=2*N;
  6. char buf[SZ],*ie=buf+SZ,*ip=ie-1;
  7. inline int in(){
  8. G;while(*ip<'-')G;
  9. R x=*ip&15;G;
  10. while(*ip>'-'){x*=10;x+=*ip&15;G;}
  11. return x;
  12. }
  13. int he[N],ne[M],to[M],f[N],a[N],b[N];
  14. int Getf(R x){
  15. return x==f[x]?x:f[x]=Getf(f[x]);
  16. }
  17. void Dfs(R x,R op){
  18. a[x]=op;
  19. for(R y,i=he[x];i;i=ne[i])
  20. if((y=to[i])!=f[x])
  21. f[y]=x,Dfs(y,-op),a[x]+=a[y];
  22. }
  23. int main(){
  24. R n=in(),m=in(),rt=1,re=1,p=0,ans=0;
  25. for(R i=1;i<=n;++i)f[i]=i;
  26. for(R p=0,i=1;i<=m;++i){
  27. R x=in(),y=in();
  28. if(Getf(x)!=Getf(y))f[f[x]]=f[y];
  29. else{rt=x,re=y;continue;}//把多的边单独拿出来
  30. ne[++p]=he[x];to[he[x]=p]=y;
  31. ne[++p]=he[y];to[he[y]=p]=x;
  32. }
  33. f[rt]=0;Dfs(rt,1);
  34. if(n==m){//基环树
  35. for(R x=re;x;x=f[x])b[++p]=a[x];
  36. if(p&1){//奇环
  37. if(a[rt]&1)return puts("-1"),0;
  38. for(R x=re;x;x=f[x])a[x]-=a[rt]>>1;
  39. }
  40. else{//偶环
  41. if(a[rt])return puts("-1"),0;
  42. sort(b+1,b+p+1);
  43. for(R x=re;x;x=f[x])a[x]-=b[p>>1];
  44. }
  45. }//树
  46. else if(a[rt])return puts("-1"),0;
  47. for(R i=1;i<=n;++i)ans+=abs(a[i]);
  48. return cout<<ans<<endl,0;
  49. }

洛谷AT2046 Namori(思维,基环树,树形DP)的更多相关文章

  1. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

  2. 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门

    dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...

  3. 洛谷 P7163 - [COCI2020-2021#2] Svjetlo(树形 dp)

    洛谷题面传送门 神仙级别的树形 dp. u1s1 这种代码很短但巨难理解的题简直是我的梦魇 首先这种题目一看就非常可以 DP 的样子,但直接一维状态的 DP 显然无法表示所有情况.注意到对于这类统计一 ...

  4. BZOJ 1040 [ZJOI2008]骑士 (基环树+树形DP)

    <题目链接> 题目大意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的 ...

  5. 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)

    洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...

  6. 骑士 HYSBZ - 1040(基环树+树形dp)

    Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...

  7. BZOJ 1040 骑士 基环树 树形DP

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目大意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫 ...

  8. 洛谷P1352 没有上司的舞会——树形DP

    第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...

  9. bzoj 1040: [ZJOI2008]骑士【基环树+树形dp】

    没考虑可以连着两个不选--直接染色了 实际上是基环森林,对于每棵基环树,dfs找出一个环边,然后断掉这条边,分别对这条边的两端点做一边treedp,取max加进答案里 treedp是设f[u]为选u点 ...

随机推荐

  1. matplotlib中subplot的使用

    #plt.subplot的使用 import numpy as npimport matplotlib.pyplot as pltx=[1,2,3,4]y=[5,4,3,2]plt.subplot(2 ...

  2. DelegatingFilterProxy作用浅析

    <filter> <filter-name>secondDomainFilter</filter-name> <filter-class>org.spr ...

  3. elasticSearch聚合sum查询

    有时需要统计一段时间内,订单的总金额.类似于sql的sum,针对某一字段求和.这就涉及到es的聚合查询,来看看用spring-data-elasticSearch怎么写:   QueryBuilder ...

  4. 福州大学软件工程1816 | W班 第7次作业成绩排名

    写在前面 汇总成绩排名链接 1.作业链接 第七次作业--项目需求分析(团队) 2.评分准则 本次作业映射总分为100分+贡献度得分,由以下部分组成: 引言(5 points) . 用户场景(15 po ...

  5. Pycharm中怎么给字典中的多个键-值对同时加上单引号

    今天看了个爬虫视频,崔庆才讲师的免费视频, 里面一个批量给header加引号2s完成,这波操作让我眼前一亮. 最终还是发现了骚操作的背后手速是真的快. pycharm中按ctrl+r 勾选右上角的Re ...

  6. 《Effective C++》让自己习惯C++:条款1-条款4

    条款1:视C++为一个语言联邦 可以将C++分为4个层次: 1.C:C++实在C语言的基础上发展而来的. 2:Object-Oriented C++:C++面向对象. 3:Template C++:C ...

  7. bootstrap模态框modal使用remote动态加载内容,第二次加载显示相同内容解决办法

    bootstrap的modal中,使用remote可以动态加载页面到modal-body中,并弹窗显示 如果提供的是 URL,将利用 jQuery 的 load 方法从此 URL 地址加载要展示的内容 ...

  8. vue-cli项目开发/生产环境代理实现跨域请求+webpack配置开发/生产环境的接口地址

    一.开发环境中跨域 使用 Vue-cli 创建的项目,开发地址是 localhost:8080,需要访问非本机上的接口http://10.1.0.34:8000/queryRole.不同域名之间的访问 ...

  9. fiddler 笔记-重定向

    重定向功能:主要是进行会话的拦截,然后替换原始资源的功能 选择请求-到autoresponser面板-勾选 enable rules :add rules 设置如下: 2 在浏览器中请示url-页面跳 ...

  10. jdbc工具类2..0

    一.创建外部文件 url=jdbc:mysql:///qy66 use=root password=root driver=com.mysql.jdbc.Driver 二.创建工具类 package ...