7.23开始
看字数分文章吧10000字一篇不然太难找了了;
P5021 NOIP2018
这道题刚看见的时候读不懂这题是啥意思,多读了几遍才知道,然后想了想骗分只能骗到55而且也挺好写的,后来就不知道怎么做了,50的范围我都想不出什么狗屁方法,想了一个小时之后,然后去看题解了,发现这题其实很简单,只是我刷题太少人比较笨想不出来;
二分答案基本上是可以肯定了的,好像最大值最小和最小值最大基本没有逃出过二分的范围,之前还怀疑会不会二分只是一种解答而已,题目中给了个限制叫做选的赛道的条数,这个条件很重要就是拿来check的基础,刚开始做的时候我甚至想到这点都有点困难,然后分析一下用那种二分;
树上处理的问题被标签迷惑了,一直在想lca能怎么做,后来发现这就是多此一举根本用不到lca;
阅读了几个阳间题解,觉得下面几句话写得很好:
3.题目中的这句话“一条赛道是一组互不相同的道路 ,满足可以从某个路口出发,依次经过这些道路(每条道路经过一次,不允许调头)到达另一个路口。”给了我们第一个提示:对于一个节点,与和它相连的子节点之间,最多只能选取两条边组成赛道。因为如果边数超过2,很明显是无法在不掉头的情况下一次性走完这条赛道的。(比如下图)
4.题目中的这句话“要求每条道路至多被一条赛道经过”给了我们第二个提示:对于一个节点,与和它相连的子节点未被选取的边中,最多只有一条可以对之后的答案做出贡献,我们只要把这条边的的长度向上传递就好。因为该节点与它父节点之间只有一条边,只可以建立一条赛道。(比如下图)
这个解读狠不戳;
题目的数据范围表格给了启发,其实就是菊花图和二叉树或链的结合一下,就是说一部分是直接可以在当前节点上直接了解,另一部分要一直延伸上去;
还有一张图画得很好;
很形象地解构出来了,以后做题的时候可以参考一下做法,前面想的时候就光想了。
这题目的精髓是其结构这棵树的方式比较奇特;既有挂在一个节点上的链也有伸上去的很有启发意义;
做这题时候的缺陷就是没有很确定的想到二分时候怎么去check,如果想到的话那么会效率更高的想到后面的步骤;
可以和树网的核类比一下都是树上问题;
反思一下,这两道题看了题解都很简单,之所以做不出来就是check函数的设计出了问题,其实多仔细想想就能解决的东西;
代码
我们可以证明这个代码的正确性;
证明略;
学学这个代码的细节处理还是很妙的;
对我这种想不来更写不来的菜逼来说;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define debug puts("OK")
const int INF = 0x3f3f3f3f,N = 5e4+10, M = 1e5+100;
int h[N],w[M],ne[M],e[M],idx;
void add(int a,int b,int c){
e[idx] = b, w[idx] = c,ne[idx] = h[a], h[a] = idx++;
}
int n,m,res,tail;
int que[M],dp[M],tag[M];
void dfs(int u,int fa,int x){
for(int i = h[u];~i;i = ne[i])
if(e[i] != fa)
dfs(e[i],u,x);
tail = 0;
for(int i= h[u];~i;i=ne[i]){
if(e[i]!= fa)
que[++tail] = dp[e[i]] + w[i];
// printf("%d\n",que[tail]);
}
sort(que+1,que+tail+1);
for(int i = tail; i>=1&&que[i] >= x;i--){
tail -- ,res -- ;
}
for(int i = 1;i<=tail;i++){
if(tag[i]!= u){
int l = i+1, r = tail , pst = tail + 1;
while(l<=r){
int mid = (l+r) >> 1;
if(que[i] + que[mid] >= x){
pst = mid , r = mid -1;
}else l = mid + 1;
}
while(tag[pst] == u &&pst<=tail){
pst ++ ;
}
if(pst <= tail)
tag[i] = tag [pst] = u, res--;
}
}
dp[u] = 0;
for(int i = tail;i >= 1;i--){
if(tag[i] != u){
dp[u] = que[i];
break;
}
}
return;
}bool check(int x){
res = m;
memset(tag,0,sizeof tag)