并不对劲的bzoj3677:p3647:[APIO2014]连珠线
题目大意
有一种生成\(n\)个点的树的方法为:
一开始有一个点,\(n-1\)次操作,每次可以有两种操作:1.选一个点,用一条红边将它与新点连接;2.将新点放在一条红边上,新点与这条红边两端点直接的连边变成蓝色
给出一个\(n(n\leq 2\times10^5)\)个点的树,问如何分配边的颜色使这棵树能用上述方法生成,而且蓝边权值之和最大
题解
(想要简明且优秀的题解点这里)
考虑那种生成方法,发现每条蓝边肯定是由一条红边“分裂”的,那就可以把“连红边”和“分裂红边”放在一起考虑
将初始点当根,那么想要生成蓝边时,一定会生成一条长度为2的蓝色直链
即确定根之后,存在一种方案将所有蓝边划分成若干条长为2的直链
考虑换根dp,发现不想写
先随便找一个点当“假根”
发现在考虑点\(u\)时,根具体在哪不影响答案,但根是在 \(u\)除自己以外的子树中 还是 在\(u\)或\(u\)的子树外 会影响过点\(u\)的蓝直链形态
\(u\)是否是蓝直链的中点也会影响
那么就可以设\(f(u,i,j)\)表示考虑点\(u\)时,根在/不在\(u\)除自己以外的子树中,且\(u\)是/不是中点
又发现当根在\(u\)除自己以外的子树中,且\(u\)为中点,且过它的蓝直链在假根看来是弯链,这样它的转移就会和 过它的蓝直链在假根看来是弯链 不同
所以\(u\)就会有5个状态:\(f(u,0,0),f(u,0,1),f(u,1,0),f(u,1,1)\)(过它的直链在假根看来是弯链)\(,f(u,1,2)\)(过它的直链在假根看来是直链)
多乎哉?不多也
下面考虑如何得到\(f(u,i,j)\)
发现得到\(f(u,1,1)\)需要像儿子中连2条作为过它的蓝直链的边,\(f(u,0,1),f(u,1,2)\)需要连1条作为过它的蓝直链的边,那就需要把“实际连了几条边”记在状态里
当根在\(u\)除自己以外的子树中时,还要记当前是否有根出现在儿子的子树中
所以为了求出\(f(u,i,j)\),要再给\(u\)设\(g(u,i,j,k)\),其中\(k\)表示是否已经有根出现在子树中:\(g(u,0,0,k)\),\(g(u,0,1,k)\),\(g(u,0,2,k)\),\(g(u,1,0,k)\),\(g(u,1,1,k)\),\(g(u,1,2,k)\),\(g(u,1,3,k)\),\(g(u,1,4,k)\),\(g(u,1,5,k)\)
其中:
\(g(u,0,0,k)\)同\(f(u,0,0)\)
\(g(u,0,1,k),g(u,0,2,k)\)表示想要达到\(f(u,0,1)\)的状态,实际连了0或1条作为过它的蓝直链的边
\(g(u,1,0,k)\)同\(f(u,1,0)\)
\(g(u,1,1,k),g(u,1,2,k),g(u,1,3,k)\)表示想要达到\(f(u,1,1)\)的状态,实际连了0或1或2条作为过它的蓝直链的边
\(g(u,1,4,k),g(u,1,5,k)\)表示想要达到\(f(u,1,2)\)的状态,实际连了0或1条作为过它的蓝直链的边
多乎哉?不多也
接下来考虑转移,设\(v\)为当前考虑到的\(u\)的儿子
要注意的是,\(v\)作为中点且过\(v\)的蓝直链在假根看来也是直链时,\(u,v\)之间必须为蓝边
如果\(u,v\)都不是中点,那么它们之间的边不能为红
具体转移见代码
最后的答案是\(max( f(假根,0, 0), f(假根, 1, 0), f(假根, 1, 1) )\),因为假根没有父亲,而\(f(u,0,1),f(u,1,2)\)需要\(u\)与\(u\)的父亲之间连蓝边
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200010
#define maxm (maxn<<1)
#define inf 2147483647
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int n,g[3][6][2],t[3][6][2],f[maxn][2][3],fir[maxn],v[maxm],nxt[maxm],cnt,w[maxm];
void ade(int u1,int v1,int w1){v[cnt]=v1,nxt[cnt]=fir[u1],w[cnt]=w1,fir[u1]=cnt++;}
int add(int x,int y){if(x==-inf||y==-inf)return -inf;return x+y;}
#define upd(x,y) x=max(x,y)
void getans(int u,int fa)
{
view(u,k)if(v[k]!=fa)getans(v[k],u);
rep(i,0,1)rep(j,0,5)rep(k,0,1)g[i][j][k]=-inf;
g[0][0][0]=g[0][1][0]=g[1][0][0]=g[1][1][0]=g[1][4][0]=0;
view(u,k)if(v[k]!=fa)
{
rep(i,0,2)t[0][i][0]=g[0][i][0];
rep(i,0,5)rep(l,0,1)t[1][i][l]=g[1][i][l];
//一、边(u,v)为红:
//1.根不在v子树中
rep(i,0,2)upd(g[0][i][0],add(t[0][i][0],f[v[k]][0][0]));
rep(i,0,5)rep(l,0,1)upd(g[1][i][l],add(t[1][i][l],f[v[k]][0][0]));
//2.根在v子树中
//当过u的蓝直链在假根看来是直链时,在v中的根看来一定是弯链,所以没有到g(u,1,1/2/3/4/5,0/1)的转移
upd(g[1][0][1],add(t[1][0][0],max(f[v[k]][1][1],f[v[k]][1][0])));
//二、边(u,v)为蓝
//1.根不在v子树中
rep(i,0,2)upd(g[0][i][0],add(add(t[0][i][0],f[v[k]][0][1]),w[k]));
rep(i,0,5)rep(l,0,1)upd(g[1][i][l],add(add(t[1][i][l],f[v[k]][0][1]),w[k]));
rep(l,0,1)
{
upd(g[0][2][l],add(add(t[0][1][l],f[v[k]][0][0]),w[k]));
upd(g[1][2][l],add(add(t[1][1][l],f[v[k]][0][0]),w[k]));
upd(g[1][3][l],add(add(t[1][2][l],f[v[k]][0][0]),w[k]));
upd(g[1][5][l],add(add(t[1][4][l],f[v[k]][0][0]),w[k]));
}
// 2.根在v子树中
upd(g[1][0][1],add(add(t[1][0][0],f[v[k]][1][2]),w[k]));
upd(g[1][2][1],add(add(t[1][1][0],max(f[v[k]][1][0],f[v[k]][1][1])),w[k]));
upd(g[1][3][1],add(add(t[1][2][0],max(f[v[k]][1][0],f[v[k]][1][1])),w[k]));
upd(g[1][5][1],add(add(t[1][4][0],max(f[v[k]][1][0],f[v[k]][1][1])),w[k]));
}
f[u][0][0]=g[0][0][0],f[u][0][1]=g[0][2][0],f[u][1][0]=max(0,g[1][0][1]),
//f(u,1,0)实际意义是“根在u子树中除u以外的区域时的答案” (即u没儿子时为-inf)
//但当它转移到u的父亲时,它的意义是 “根在u子树中时的答案”(即u没儿子时为0)
//而且最终答案最小值为0,所以在这里将它改为0不影响统计答案
f[u][1][1]=g[1][3][1],f[u][1][2]=g[1][5][1];
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read();
rep(i,1,n-1){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);}
getans(1,0);
write(max(f[1][0][0],max(f[1][1][0],f[1][1][1])));
return 0;
}
/*
5
1 2 10
1 3 40
1 4 15
1 5 20
*/
一些感想
换根dp可以记一位状态表示“真的根在不在该子树里”。
并不对劲的bzoj3677:p3647:[APIO2014]连珠线的更多相关文章
- 【BZOJ3677】[Apio2014]连珠线 换根DP
[BZOJ3677][Apio2014]连珠线 Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色 ...
- Luogu P3647 [APIO2014]连珠线
题目 换根dp. 显然对于给定的一棵有根树,蓝线都不能拐弯. 设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案.(以\(1 ...
- 洛谷$P3647\ [APIO2014]$连珠线 换根$dp$
正解:换根$dp$ 解题报告: 传送门! 谁能想到$9102$年了$gql$居然还没写过换根$dp$呢,,,$/kel$ 考虑固定了从哪个点开始之后,以这个点作为根,蓝线只可能是直上直下的,形如&qu ...
- [换根DP]luogu P3647 [APIO2014]连珠线
题面 https://www.luogu.com.cn/problem/P3647 不重复地取树中相邻的两条边,每次得分为两条边权和,问最大得分 分析 容易想到状态 f[i][0/1] 分别表示 i ...
- 洛谷 P3647 [APIO2014]连珠线(换根 dp)
题面传送门 题意: 桌子上有 \(1\) 个珠子,你要进行 \(n-1\) 次操作,每次操作有以下两种类型: 拿出一个新珠子,并选择一个桌子上的珠子,在它们之间连一条红线 选择两个由红线相连的珠子 \ ...
- [Bzoj3677][Apio2014]连珠线(树形dp)
3677: [Apio2014]连珠线 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 434 Solved: 270[Submit][Status] ...
- 【LG3647】[APIO2014]连珠线
[LG3647][APIO2014]连珠线 题面 洛谷 题解 首先考虑一下蓝线连起来的情况,一定是儿子-父亲-另一个儿子或者是儿子-父亲-父亲的父亲. 而因为一开始只有一个点在当前局面上,将一条红边变 ...
- 题解 [APIO2014]连珠线
题解 [APIO2014]连珠线 题面 解析 首先这连成的是一棵树啊. 并且\(yy\)一下,如果钦定一个根, 那么这上面的蓝线都是爸爸->儿子->孙子这样的,因为像下图这样的构造不出来: ...
- bzoj3677: [Apio2014]连珠线
Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏 开始时,只有1个珠子,而接下来新的 ...
随机推荐
- SilverLight: 数据绑定(1)-绑定到数据对象
ylbtech-SilverLight-DataBinding: Binding to Data Objects(绑定到数据对象) 1.A, Building a Data Object(创建一个数 ...
- 拦截器及 Spring MVC 整合
一.实验介绍 1.1 实验内容 本节课程主要利用 Spring MVC 框架实现拦截器以及 Spring MVC 框架的整合. 1.2 实验知识点 Spring MVC 框架 拦截器 1.3 实验环境 ...
- 关于Gradle配置的小结
前言 使用 Android Studio 来开发 Android 工程的过程中,接触 Gradle 是不可避免的,比如配置签名.引入依赖等.那么 Gradle 到底是什么东西呢? Gradle 是一个 ...
- AngularJS的ng-class示例
程序下载:https://files.cnblogs.com/files/xiandedanteng/angularJSRender.rar 代码: <!DOCTYPE HTML PUBLIC ...
- update tableView contenSize
NSIndexPath *messageIndexPath = [NSIndexPath indexPathForRow:afterRowCount-1 inSection:0]; [self. ...
- java web 站点头像上传处理 (springmvc +bootstrap+cropper)
制作头像上传.请依据您的实际需求.改动代码,不全然正确.仅供參考! 前端页面设计使用bootstrap ,头像预览和剪裁工具使用cropper 后台使用springmvc. 如今来看前端的页面设计 前 ...
- mysql 查看当前连接数
http://www.cnblogs.com/pcdelphi/archive/2009/10/31/2017990.html 实战经验: >登录到mysql数据库的终端 >show ...
- [转] git clone 远程分支
git clone只能clone远程库的master分支,无法clone所有分支,解决办法如下: 找一个干净目录,假设是git_work cd git_work git clone http://my ...
- 文件另存为——Autocad.doc.SaveAs
一.前言 使用pyautocad编辑好cad图纸后,往往涉及到一个保存的问题,但是官方文档并未提及,所以只能自己来了,测试了好久,终于是找到了保存的命令和参数说明. 二.方法介绍 Autocad.do ...
- linux c 网络编程:用域名获取IP地址或者用IP获取域名 网络地址转换成整型 主机字符顺序与网络字节顺序的转换
用域名获取IP地址或者用IP获取域名 #include<stdio.h> #include<sys/socket.h> #include<netdb.h> int ...