题目链接:

闲扯:

这题考场上把子任务都敲满了,5个namespace,400行11k

结果爆0了哈哈,因为写了个假快读只能读入一位数,所以手测数据都过了,交上去全TLE了

把边分成三类:0. 需要染色的 1. 不需要染色的 2. 染不染色无所谓

考场上首先发现一个性质,就是一定存在一种最优解没有染任何一条本来不需要的染色边。

为啥?其实也挺显然的,因为你染色跨过这条边还得染这条边一次,不如直接只染左右的联通块,这样总路径长度还能更小

但是第三种边的呢?有个子任务就是枚举它染不染。

然后链上的情况就搞了个贪心的做法,如果对于一条第三种情况的边,如果两边的联通块是需要染色的,显然选这条边是更优的.但是注意考虑多条这种边连在一起的情况.

然后树上的版本贪心似乎就GG了

然后晚上盯着毫无注释std和仅有三行的题解,画了一面的草稿纸,终于看懂了...

分析:

首先我们需要假如我们已经有了最优情况的一种边集,怎么求出最小操作次数,其实是边集的点集中度数为奇数的点的个数除以2。为什么?显然最优情况下,每一个奇数度数点恰好是一条操作路径的结尾,由于一条操作路径连接两个点所以除以2

然后对于一个以x为根的子树,如果已经取得了最优解,可以通过分情况考虑更新父亲,显然是具有最优子结构的.于是使用树形DP

定义\(f[x][0/1]\)表示在以x为根的子树中,不染色/染色x与其父亲相连的最优代价

(注意代价是一个二元组\(cost(x,y)\)代表奇数点个数和染色路径总长度,这里比较代价大小根据题意,就不赘述了)

为了分情况转移我们需要求出两个值,\(npt\)是x在x为根的子树中假如x不是任意一条染色路径的端点的最优代价;\(pt\)是x在x为根的子树中假如x是某一条染色路径的端点时的最优代价(注意这里的路径端点都是从子树引出来的路径)

怎么求出\(npt\)和\(pt\)呢?我们可以将所有\(x\)的儿子\(v\)回溯到\(x\)的过程中逐个统计,接下来比较神奇可以借助图像理解

\(npt=min(npt+f[v][0],pt+f[v][1])\)

解释: 画图,若\(v\)到其父亲\(x\)边没有染色,说明原来如果x不是路径端点的话现在还不会是端点;类似的,若\(v\)到父亲\(x\)的边染色了,并且\(x\)此时是一条路径的端点,那么这时候我们可以把路径延长到\(v\)的子树中,这样是解更优并且\(x\)这样就不会是路径端点了

\(pt = min(npt+f[v][1],pt+f[v][0])\)

解释:与上面类似就太懒不想打了,有问题可以luogu或QQ联系我

在考虑DP中\(f\)数组的转移

再强调一下定义:定义\(f[x][0/1]\)表示在以x为根的子树中,不染色/染色x与其父亲相连的最优代价

设\(x\)与其父亲相连的边的属性为\(p\)

首先根据在"闲扯"中的性质以及题意,若\(p=1,f[now][1]=(inf,inf)\);若\(p=0,f[now][0]=(inf,inf)\)

然后现在先考虑\(f[now][0]\),\(f[now][0]=min(npt,cost(pt.x+1,pt.y))\) , 这里的\(cost\)可以理解为\(make\)_\(pair\)

解释:如果\(x\)不是染色路径的端点,而且x到父亲的边也不染色,那么显然代价不变.但是如果\(x\)是某一条路径的端点,那么这时候我们需要加上\(x\)这个点的贡献(它是个端点那肯定是奇数度数)

再考虑\(f[now][1],f[now][1]=min(cost(npt.x+1,npt+1),cost(pt.x,pt.y+1))\)

解释:如果\(x\)不是路径端点,那么\(x\)如果和父亲相连的边染色的需要新开一条路径,所以见上;如果\(x\)是路径端点,那么我们可以把这条路径引上去,x点的贡献就不用计算,只需要让路径长度加1就好了

然后就没了,代码很短但很难想

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
#define ll long long
#define ri register int
using std::min;
using std::max;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=100005;
const int inf=0x7ffffff;
struct Edge{
int ne,to,w;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to,int x){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
edge[num_edge].w=x;
h[f]=num_edge;
}
struct Dat{
int x,y;
Dat(){x=y=inf;}
Dat(int _x,int _y){x=_x,y=_y;}
Dat operator +(const Dat &b)const{
return Dat(x+b.x,y+b.y);
}
bool operator <(const Dat &b)const{
return x==b.x?y<b.y:x<b.x;
}
}f[maxn][2];
int n;
void dfs(int now,int fa,int t){
int v;
Dat npt=Dat(0,0),pt=Dat(inf,inf);//npt--不是路径端点 pt是路径端点
Dat pa=Dat(0,0),pb=Dat(0,0);
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa)continue;
dfs(v,now,edge[i].w);
pa=min(npt+f[v][0],pt+f[v][1]);
pb=min(npt+f[v][1],pt+f[v][0]);
npt=pa,pt=pb;
}
if(t==1)f[now][0]=Dat(inf,inf);//必须要翻转
else {
f[now][0]=min(npt,Dat(pt.x+1,pt.y));
}
if(t==0)f[now][1]=Dat(inf,inf);//性质--翻转1边一定更不优
else {
f[now][1]=min(Dat(npt.x+1,npt.y+1),Dat(pt.x,pt.y+1));
}
return;
}
int main(){
int x,y,c,d;
freopen("w.in","r",stdin);
freopen("w.out","w",stdout);
read(n);
for(ri i=1;i<n;i++){
read(x),read(y),read(c),read(d);
if(d==2){
add_edge(x,y,2),add_edge(y,x,2);
}
else {
d=c^d;
add_edge(x,y,d),add_edge(y,x,d);
}
}
dfs(1,0,0);
Dat ans=min(f[1][0],f[1][1]);
printf("%d %d\n",ans.x/2,ans.y);
return 0;
}

[NOIP10.3模拟赛]3.w题解--神奇树形DP的更多相关文章

  1. [NOIP10.6模拟赛]2.equation题解--DFS序+线段树

    题目链接: 咕 闲扯: 终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ 首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解 然而考场上只得了86 ...

  2. [NOIP10.4模拟赛]3.z题解--思维

    题目链接: 咕咕 闲扯: 哈哈这道T3考场上又敲了5个namespace,300+行,有了前车之鉴还对拍过,本以为子任务分稳了 结果只有30分哈哈,明明用极限数据对拍过不知怎么回事最后数据又是读不全, ...

  3. [NOIP10.6模拟赛]1.merchant题解--思维+二分

    题目链接: while(1)gugu(while(1)) 闲扯 考场上怕T2正解写挂其他两题没管只打了暴力,晚上发现这题思维挺妙的 同时想吐槽出题人似乎热衷卡常...我的巨大常数现在显露无疑QAQ 分 ...

  4. [NOIP10.5模拟赛]1.a题解--离散化+异或线段树

    题目链接: 咕咕咕 https://www.luogu.org/problemnew/show/CF817F 闲扯 在Yali经历几天折磨后信心摧残,T1数据结构裸题考场上连暴力都TM没打满 分析 观 ...

  5. [NOIP10.4模拟赛]2.y题解--折半搜索+状压计数

    题目链接: 咕 闲扯: 这题暴力分似乎挺多,但是一些奇奇怪怪的细节没注意RE了,还是太菜了 分析: 首先我们考虑最naiive的状压DP ,\(f[u][v][state]\)表示u开头,v结尾是否存 ...

  6. [NOIP10.5模拟赛]3.c题解--思维

    题目链接 这次不咕了 https://www.luogu.org/problemnew/show/AT2389 闲扯 考场20分爆搜走人 \cy 话说这几天T3都很考验思维啊 分析 我们先钦定一只鸡( ...

  7. 【NOI P模拟赛】最短路(树形DP,树的直径)

    题面 给定一棵 n n n 个结点的无根树,每条边的边权均为 1 1 1 . 树上标记有 m m m 个互不相同的关键点,小 A \tt A A 会在这 m m m 个点中等概率随机地选择 k k k ...

  8. 【NOIP 模拟赛】Evensgn 剪树枝 树形dp

    由于树规做的少所以即使我考试想出来正确的状态也不会转移. 一般dp的转移不那么繁杂(除了插头.....),即使多那也是清晰明了的,而且按照树规的一般思路,我们是从下到上的,所以我们要尽量简洁地从儿子那 ...

  9. 校内模拟赛 : Rima —— 字典树+树形DP

    首先说一下,对一个刚学Trie树的蒟蒻来说(就是我),这道题是一道好题.Trie树比较简单,所以就不详细写了. Rima 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传 ...

随机推荐

  1. fork() 成为负担,需要淘汰 spawn

    A fork() in the road - Microsoft Research https://www.microsoft.com/en-us/research/publication/a-for ...

  2. UML期末复习题——2.5:System Sequence Diagram & Post-condition

    第五题:系统顺序图 重要概念: 1.对象: 对象是特定行为与属性的集合. 对象的表示方式有三种: a.包括对象名和类名 b.只有类名. c.只有对象名 2.消息表示形式: 消息用于描述对象间交互的方式 ...

  3. smarty获得当前url的方法分享

    http://{$smarty.server.SERVER_NAME}/{$smarty.server.REQUEST_URI} 注释: 复制代码代码如下: {$smarty.server.SERVE ...

  4. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_13-页面静态化-数据模型-轮播图DataUrl接口

    要开发轮播图的DataUrl的接口 轮播图的配置的集合 xc-framework-model这个module下 CmsConfigModel的类的属性 定义接口 在api里面定义接口:CmsConfi ...

  5. 一百三十六:CMS系统之发布帖子后台逻辑

    模型 class PostModel(db.Model): __tablename__ = 'post' id = db.Column(db.Integer, primary_key=True, au ...

  6. Java操作excel_导出与读取(导入)

    我自己的jar包下载 一.介绍 常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统.银行系统).或者是:我们已经习惯用Excel打印.这样在我们实际的开发中,很多时候需要实现导入.导 ...

  7. nginx重新编译不停服

    找到安装nginx的源码根目录,如果没有就下载新的安装包 .tar.gz 查看ngixn版本极其编译参数 /usr/local/nginx/sbin/nginx -V 进入nginx源码目录 cd n ...

  8. python基础--字符串、元组

    字符串方法 注:字符串和元组一样都是不可变的,以下函数不会改变原来字符串的值,可以将其赋给一个新的变量 st='a b c d,f,g' st_list=st.split()#字符串分割,参数不写,按 ...

  9. Map对象,Set对象使用(1)

    Map对象:包含所有类型.可以是对象,函数,或字符串等,本质上是键值对的集合 let m = new Map(); let keyarr = [1,23,"发广告"]; let k ...

  10. 【VS开发】图像颜色

    版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/lg1259156776/. 最近被图像颜色整的乱七八糟的,一会儿YUV422,一会儿RGB,一会儿gray... ...