博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[NOIP2016]天天爱跑步
阅读量:4455 次
发布时间:2019-06-07

本文共 2328 字,大约阅读时间需要 7 分钟。

description

data range

\[n\le 50\]

solution

相信几乎机房里的所有人都已经切掉了。。。

蒟蒻直到\(NOIP2018\)前夕才草草补上。。。

把路径\(u->v\)拆成\(u->lca_{u,v}\)\(lca_{u,v}->v\)两部分,

\(dep_u\)为深度,\(tim_u\)为到达节点的时间戳,
\(u->lca_{u,v}\)这部分满足\(tim_x+dep[x]\)一定,\(lca_{u,v}->v\)这部分满足\(tim_x-dep[x]\)一定,
不再赘述。

此题的另一个难点在于如何利用差分统计答案。

如果直接对一个节点打标记然后开全局\(sum\)统计的话,相当于对一棵子树打标记,而我们要打的是链标记,这样显然是不对的。
考虑我们需要打标记的链上节点,发现链头和链尾一定有且仅有一个在子树中
于是我们把贡献转换为进入树节点和离开树节点时对应全局标记的差
代码如下

void dfs(int u,int ff){    RG int cur=sum[w[u]];    for(RG int i=head[u];i;i=nxt[i]){        RG int v=to[i];if(v==ff)continue;        dfs(v,u);    }    ans[u]+=sum[w[u]]-cur;}

这样我们就能高效地维护差分信息,去掉求\(lca\)的复杂度,总复杂度为\(O(n)\)

然后说一下本蒟蒻在维护该信息的另一种略丑的方法

有了\(tim_x+dep[x]\)一定或\(tim_x-dep[x]\)一定的信息,一条链是肯定知道怎么做的
于是我们考虑把树重链剖分,依次考虑每一条重链,那么这样就可以直接转换为链上的问题来做
具体来说,差分时需要自底向上/自顶向下对每一条链进行差分,由于这样只会有\(logn\)条重链,因此这样做是\(O(mlogn)\)
最后统计答案时我们一条重链一条重链地统计,由于之前差分了\(O(mlogn)\)次,所有重链的长度之和为\(O(n)\),因此这样做是\(O(n+mlogn)\)
加上求\(lca\)的复杂度,总复杂度为\(O((n+m)logn)\),比标解略丑

Code

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define F "4719"#define mp make_pair#define pb push_back#define RG register#define il inlineusing namespace std;typedef unsigned long long ull;typedef pair
PI;typedef vector
VI;typedef long long ll;typedef double dd;const int N=3e5+10;const int M=3e5+10;const int K=3e5+10;const int mod=998244353;const int inf=2147483647;const ll INF=1ll<<60;const dd eps=1e-7;const dd pi=acos(-1);il ll read(){ RG ll data=0,w=1;RG char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar(); return data*w;}il void file(){ freopen(F".in","r",stdin); freopen(F".out","w",stdout);}int n,m,w[N];int head[N],nxt[N<<1],to[N<<1],cnt;il void add(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}int fa[N],sz[N],son[N],dep[N],top[N];int cal[N],cov;VI line[N];void dfs1(int u,int ff){ sz[u]=1;fa[u]=ff;son[u]=0;dep[u]=dep[ff]+1; for(RG int i=head[u];i;i=nxt[i]){ RG int v=to[i];if(v==ff)continue; dfs1(v,u);sz[u]+=sz[v];if(sz[son[u]]
dep[top[v]]?u=fa[top[u]]:v=fa[top[v]]; return dep[u]

转载于:https://www.cnblogs.com/cjfdf/p/9775475.html

你可能感兴趣的文章
08多态
查看>>
Groovy 程序结构
查看>>
使用 WordPress 的导航菜单
查看>>
input只能输入数字和小数点,并且只能保留小数点后两位 - CSDN博客
查看>>
js 不固定传参
查看>>
远程调试UWP遇到新错误Could not generate the root folder for app package ......
查看>>
git--windwos下的安装与使用(一)
查看>>
[倍增][最短路-Floyd][dp]
查看>>
SpringAOP用到了什么代理,以及动态代理与静态代理的区别
查看>>
利用STM32CubeMX来生成USB_HID_Mouse工程【添加ADC】(1)
查看>>
【leetcode】Populating Next Right Pointers in Each Node
查看>>
获取请求参数乱码的问题
查看>>
代码实现:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称...
查看>>
Android客户端测试点
查看>>
Jquery:怎样让子窗体的div显示在父窗体之上
查看>>
01概率
查看>>
.NET LINQ 元素操作
查看>>
Shell脚本
查看>>
MatLab Load cv::Mat 导入数据
查看>>
html+css相关笔记(一)
查看>>