传送门

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

这题什么时候再康一遍,第一次见这个样子的树形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. ESP32构建系统 (传统 GNU Make)

    概述: 一个 ESP-IDF 项目可以看作是多个不同组件的集合,ESP-IDF 可以显式地指定和配置每个组件.在构建项目的时候,构建系统会前往 ESP-IDF 目录.项目目录和用户自定义目录(可选)中 ...

  2. mybatis常用标签(转)

    1. 定义sql语句 select 标签 属性介绍: id :唯一的标识符. parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User或user resu ...

  3. OSSBrowser windows使用

    目录 1. 安装 2. 启动OSSBrowser并登录 1. 安装 下载地址:github或官方 2. 启动OSSBrowser并登录 ossbrowser安装包下载到本地解压之后,点击oss-bro ...

  4. mac-webui-selenium下的webdriver selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH

    from selenium import webdriver def test1(): url='http://www.baidu.com' driver=webdriver.Chrome(" ...

  5. MAC系统如果碰到报错信息:sudo:command not found

    ** 一般要考虑最近是否有别人或者自己修改过环境变量,这种报错往往是因为环境变量设置错误导致的. ** 1. 首先要获得创建,或者是打开bash_profile的权限,请在命令行中输入: export ...

  6. session过期跳转到登陆页面并解决跳出iframe问题

    首先,先转载如下这篇博主写的关于后台系统使用iframe不能跳出的问题,地址:https://blog.csdn.net/xiaocen99/article/details/38521649 在ifr ...

  7. [刘阳Java]_Spring常用注解介绍_第6讲

    Spring的注解是在Spring2.5的版本中引入的,目的简化XML配置.在企业开发过程中使用注解的频率非常高,但是学习注解的前提是大家一定要对Spring基于XML配置要熟悉,这是我个人建议,因为 ...

  8. 二进制方式安装 k8s

    推荐个好用的安装k8s的工具 https://github.com/easzlab/kubeasz 该工具基于二进制方式部署 k8s, 利用 ansible-playbook 实现自动化    1.1 ...

  9. Leetcode:230. 二叉搜索树中第K小的元素

    Leetcode:230. 二叉搜索树中第K小的元素 Leetcode:230. 二叉搜索树中第K小的元素 思路: 利用BST的中序历遍的结果为其排序后的结果,我们可以利用其特性直接找到第k个中序遍历 ...

  10. Servlet 单例多线程详解(六)

    一.Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...