传送门

一直觉得有点后效性什么的,也不知道怎么写

这题什么时候再康一遍,第一次见这个样子的树形DP,是个树上带不定权边的DP(???

这里能树形DP的原因好像是在这里所有子节点的状态都能表示出来

还有这里最小翻转数量可以转化为每个点翻转边的度数就挺神奇的,可以直接处理掉那几个麻烦的分类讨论

这题成链的部分分和\(d \neq 2\)的部分分其实很好做……后一个dp都不用取max,只有一种可能

全分建议再去康一眼题解

可以发现对于一个点u,如果它有一条d=2的边连到一个点v

不管这条边是否翻转,v的子树中度数为奇的点数量还有路径长度都是要原样传上来的

所以其实这条边选不选只影响u,v度数的奇偶性

而对v的影响其实即为其父节点与它是否连边,这个在设计状态的时候已经考虑进去了

所以只需要开两个二元组分别记录这个点连出的边数是奇数还是偶数时的最小值就行了

随时默念「奇加奇等于偶,偶加奇等于奇」能避免很多智障错误……

细节极多,写了5个小时……

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
} int n;
int head[N], size, cnt[N];
struct edge{int to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {edge* k=&e[++size]; k->to=t; k->val=w; k->next=head[s]; head[s]=size;} namespace force{
bool vis[N], cge[N], mer[N], len;
void dfs(int u, int fa) {
//cout<<"dfs "<<u<<' '<<fa<<endl;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs(v, u);
if (e[i].val==1) {
if (vis[v]) continue;
else {
if (vis[u]==1) {continue;}
else {vis[u]=1; ++cnt[u];}
}
}
}
}
void solve() {
dfs(1, 0);
int ans=0;
for (int i=1; i<=n; ++i) ans+=cnt[i];
cout<<ans<<' '<<len<<endl;
exit(0);
}
} namespace task1{
int v[N], cnt, len;
void solve() {
for (int i=1; i<n; ++i) v[i]=e[head[i]].val;
int lst=-1, clen=0;
bool con=0, other=0;
for (int i=1; i<=n; ++i) {
if (v[i]==1) {
if (v[i]!=lst) {
if (con) len+=clen+1, lst=v[i];
else ++cnt, ++len, lst=v[i];
}
else ++len;
other=0; con=0; clen=0;
}
else if (!v[i]) con=0, other=1, clen=0;
else {
if (lst==1 && !other) con=1, clen=1, other=0;
if (lst==2 && !other) ++clen;
if (lst==0) con=0, clen=0, other=1;
}
lst=v[i];
}
cout<<cnt<<' '<<len<<endl;
exit(0);
}
} namespace task2{
struct sit{int cnt, len; inline void build(int c_, int l_) {cnt=c_; len=l_;}}dp[N][2];
void dfs(int u, int fa) {
int minn=INF, dlt=0;
int t1, t2;
// fa->0
int cnta1=0, cnta2=0, len1=0;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs(v, u);
if (e[i].val==1) {
++cnta1; cnta2+=dp[v][1].cnt; len1+=dp[v][1].len+1;
}
else if (!e[i].val) {
cnta2+=dp[v][0].cnt; len1+=dp[v][0].len;
}
}
dp[u][0].build(cnta2+(cnta1%2), len1);
// fa->1
int cntb1=1, cntb2=0, len2=0;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
if (e[i].val==1) {
++cntb1; cntb2+=dp[v][1].cnt; len2+=dp[v][1].len+1;
}
else if (!e[i].val) {
cntb2+=dp[v][0].cnt; len2+=dp[v][0].len;
}
}
dp[u][1].build(cntb2+(cntb1%2), len2);
}
void solve() {
dfs(1, 0);
#if 1
cout<<"---dp---"<<endl;
for (int i=1; i<=n; ++i) cout<<dp[i][0].cnt<<' '<<dp[i][0].len<<' '<<dp[i][1].cnt<<' '<<dp[i][1].len<<endl;
cout<<"---dp---"<<endl;
#endif
printf("%d %d\n", dp[1][0].cnt/2, dp[1][0].len);
exit(0);
}
} namespace task{
struct sit{int cnt, len; inline void build(int c_, int l_) {cnt=c_; len=l_;}}dp[N][2];
inline bool operator < (sit a, sit b) {return a.cnt==b.cnt?a.len<b.len:a.cnt<b.cnt;}
inline bool cmp(int cnta, int lena, int cntb, int lenb) {return cnta==cntb?lena<lenb:cnta<cntb;}
void dfs(int u, int fa) {
int cnta2=0, len1=0;
int cntb2=0, len2=0;
int cnt[2]={0, INF}, len[2]={0, INF};
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs(v, u);
cnta2=cnt[0], len1=len[0];
cntb2=cnt[1], len2=len[1];
if (e[i].val==1) {
cnt[1]=cnta2+dp[v][1].cnt, len[1]=len1+dp[v][1].len+1;
cnt[0]=cntb2+dp[v][1].cnt, len[0]=len2+dp[v][1].len+1;
}
else if (!e[i].val) {
cnt[0]=cnta2+dp[v][0].cnt, len[0]=len1+dp[v][0].len;
cnt[1]=cntb2+dp[v][0].cnt, len[1]=len2+dp[v][0].len;
}
else { if (cmp(cnta2+dp[v][0].cnt, len1+dp[v][0].len, cntb2+dp[v][1].cnt, len2+dp[v][1].len+1))
cnt[0]=cnta2+dp[v][0].cnt, len[0]=len1+dp[v][0].len;
else cnt[0]=cntb2+dp[v][1].cnt, len[0]=len2+dp[v][1].len+1; if (cmp(cntb2+dp[v][0].cnt, len2+dp[v][0].len, cnta2+dp[v][1].cnt, len1+dp[v][1].len+1))
cnt[1]=cntb2+dp[v][0].cnt, len[1]=len2+dp[v][0].len;
else cnt[1]=cnta2+dp[v][1].cnt, len[1]=len1+dp[v][1].len+1;
}
}
//assert(cnt[0]==cnt[1]); if (cmp(cnt[0], len[0], cnt[1]+1, len[1]))
dp[u][0].build(cnt[0], len[0]);
else dp[u][0].build(cnt[1]+1, len[1]); if (cmp(cnt[0]+1, len[0], cnt[1], len[1]))
dp[u][1].build(cnt[0]+1, len[0]);
else dp[u][1].build(cnt[1], len[1]); //dp[u][0].build(cnt[0], len[0]);
//dp[u][1].build(cnt[1]+1, len[1]);
}
void solve() {
dfs(1, 0);
#if 0
cout<<"---dp---"<<endl;
for (int i=1; i<=n; ++i) cout<<dp[i][0].cnt<<' '<<dp[i][0].len<<' '<<dp[i][1].cnt<<' '<<dp[i][1].len<<endl;
cout<<"---dp---"<<endl;
#endif
printf("%d %d\n", dp[1][0].cnt/2, dp[1][0].len);
exit(0);
}
} signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
bool flag=1, chain=1; n=read();
for (int i=1,a,b,c,d; i<n; ++i) {
a=read(); b=read(); c=read(); d=read();
if (d==2) add(a, b, 2), add(b, a, 2);
else {add(a, b, c^d), add(b, a, c^d); flag=0;}
if (b!=a+1) chain=0;
}
//if (flag) {puts("0 0"); return 0;}
//if (chain) task1::solve();
//force::solve();
//task2::solve();
task::solve(); return 0;
}

题解 w的更多相关文章

  1. [codevs1157]2^k进制数

    [codevs1157]2k进制数 试题描述 设r是个2k 进制数,并满足以下条件: (1)r至少是个2位的2k 进制数. (2)作为2k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. ...

  2. $exLucas$学习笔记

    本来不打算写了的,,,但是感$jio$理解起来还是有点儿难度的来着,,,$so$还是瞎写点儿趴$QAQ$ $exLucas$主要有三步: 1)唯一分解$mod$并预处理$p^{k}$以内的阶乘 2)计 ...

  3. lucene入门创建索引——(二)

    1.程序宏观结构图

  4. [NOIP10.3模拟赛]3.w题解--神奇树形DP

    题目链接: 咕 闲扯: 这题考场上把子任务都敲满了,5个namespace,400行11k 结果爆0了哈哈,因为写了个假快读只能读入一位数,所以手测数据都过了,交上去全TLE了 把边分成三类:0. 需 ...

  5. csp-s模拟测试53u,v,w题解

    题面:https://www.cnblogs.com/Juve/articles/11602450.html u: 用差分优化修改 二维差分:给(x1,y1),(x2,y2)加上s: $d[x1][y ...

  6. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  7. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  8. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  9. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

随机推荐

  1. 关于vector.size()的一些常见错误总结

    1. 问题引入 通过查看[https://www.cplusplus.com/reference/vector/vector/] 的vector.size()说明,即 member type defi ...

  2. ESP32智能配网笔记

    基于ESP-IDF4.1 #include <string.h> #include <stdlib.h> #include "freertos/FreeRTOS.h& ...

  3. 痞子衡嵌入式:串行NOR Flash的页编程模式对于量产时间的影响

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是串行NOR Flash的页编程模式对于量产时间的影响. 任何嵌入式产品最终都绕不开量产效率话题,尤其是对于主控是非内置 Flash 型 ...

  4. php-18个魔法函数

    目录 php魔法函数 介绍 范例 1.__construct() 2.__destruct() 3.__call() 4.__callStatic 5.__get() 6.__set() 7.__is ...

  5. deepin安装Motrix,cocomusic

    1,motrix(下载工具):https://motrix.app/ 2,cocomusic(开源音乐播放器):https://github.com/xtuJSer/CoCoMusic/release ...

  6. C#中使用jieba.NET、WordCloudSharp制作词云图

    目录 词云简介 准备工作 基本算法 算法实现 运行测试 参考资料 词云简介 "词云"由美国西北大学新闻学副教授.新媒体专业主任里奇·戈登(Rich Gordon)于2006年最先使 ...

  7. 【动画消消乐】HTML+CSS 自定义加载动画:怦然心跳 066

    前言 Hello!小伙伴! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出-   自我介绍 ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计 ...

  8. powerdesigner连接postgresql数据库生成pdm及word文档

    1.准备软件: powerdesigner165与postgresql的驱动:psqlodbc_11_01_0000 2.安装并破解完成powerdesigner165 参看链接:https://ww ...

  9. SpringBoot之yaml语法及静态资源访问

    配置文件-yaml 在spring Boot开发中推荐使用yaml来作为配置文件. 基本语法: key: value:kv之间有空格 大小写敏感 使用缩进表示层级关系 缩进不允许使用tab,只允许空格 ...

  10. [XIN算法应用]NOI2020美食家

    XIN(\(updated 2021.6.4\)) 对于很多很多的题目,发现自己并不会之后,往往会直接冲上一个XIN队算法,然而,这样 \(\huge{\text{鲁莽}}\) 的行为只能获得 TLE ...