还有两天就要去FJWC啦…

题意:一颗无根树,$k$为给定常数,求树上距离不超过$k$的点对的数量,多组数据,$n \leq 10^4$.


应该是点分治经典题~

一般对于无根树我们都可以把它转变成有根树(其实树上路径不管哪个根都一样嘛),假设我们已经钦定了一个根$rot$(后面会说其实这个根应该是重心),对于$rot$这颗树中的对答案有贡献的路径,要么经过$rot$,要么直接就是$rot$的某一颗子树的答案,这两种情况之间没有交集直接相加,这里就出现了子问题。

而对于经过$rot$的路径的贡献,对可以通过处理一遍$rot$的子树里到它的距离$dis[]$在$O(nlogn)$时间内统计(具体见代码,其实就排个序然后扫描)。这样对于每个点我们只要找根,处理经过$rot$的路径的答案(1),删除$rot$然后递归对$rot$的所有相邻点$cur$递归的求答案(2),不过这里出现了重复计算(设$w$为当前点到相邻点$cur$的边的长度):在(1)当中其实重复计算了$cur$里满足$dis[x]+w+dis[y]+w \leq k$的点对多算了,所以我们还要减掉这种答案(你问我怎么减?看代码啦~)

实现删除的时候有个trick就是用一个数组$vis[]$来记录这个点处理过没…处理过了直接不管它。

时间复杂度?假设最多递归了$T$层,计算每一层的答案一定不超过$O(nlogn)$,总复杂度就变成了$O(T*nlogn)$。如果随便钦定某个根递归层数太大的话会被卡成$O(n^2logn)$的,嗯那么要让递归层数小的话当然就选择这个子树的重心啦~每次$O(n)$的算重心,这样$x$的所有子树的大小都不会超过整棵树大小的一半,所以深度就是$(logn)$的了,总复杂度$O(nlog^2 n)$~

呼~

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,n) for(register int i=1;i<=n;i++)
using namespace std;
const int N=10005;
inline int read()
{
int s=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
return f?s:-s;
}
struct edge
{
int to,nxt,w;
edge(int to=0,int nxt=0,int w=0):to(to),nxt(nxt),w(w){}
}edges[N<<1];
int n,k,cnt,tot;
int head[N<<1],dis[N],size[N],g[N],vis[N]; inline void addEdge(int u,int v,int w)
{
edges[++cnt]=edge(v,head[u],w);
head[u]=cnt;
}
#define cur edges[i].to
inline void dfs_root(int x,int f)
{
size[x]=1;g[x]=0;
for(register int i=head[x];i;i=edges[i].nxt)if(!vis[cur]&&cur!=f)
{
dfs_root(cur,x);size[x]+=size[cur];
g[x]=max(g[x],size[cur]);
}
}
inline int calc_root(int x,int f,int rot)
{
int res=0,minx=n;
for(register int i=head[x];i;i=edges[i].nxt)if(!vis[cur]&&cur!=f)
{
int tmp=calc_root(cur,x,rot);
if(g[tmp]<minx)minx=g[tmp],res=tmp;
}
g[x]=max(g[x],size[rot]-size[x]);
if(g[x]<minx)minx=g[x],res=x;
return res;
}
inline int get_root(int x)
{
dfs_root(x,-1);
return calc_root(x,-1,x);
}
inline void dfs_dis(int x,int d,int f)
{
dis[++tot]=d;
for(register int i=head[x];i;i=edges[i].nxt)
if(!vis[cur]&&cur!=f)dfs_dis(cur,d+edges[i].w,x);
}
inline int calc(int x,int w)
{
tot=0;
dfs_dis(x,w,-1);sort(dis+1,dis+tot+1);
int j=tot,res=0;
for(register int i=1;i<=j;i++)
{
while(i<j&&dis[i]+dis[j]>k)j--;
res+=j-i;
}return res;
}
inline int dfs(int x)
{
int rot=get_root(x),res=0;
vis[rot]=1;
res+=calc(rot,0);
for(register int i=head[rot];i;i=edges[i].nxt)if(!vis[cur])
{
res-=calc(cur,edges[i].w);//算距离的时候多加个变量就行啦
//注意不要把两种合起来写…一个是rot的子树一个是cur的子树
res+=dfs(cur);
}
return res;
} #undef cur
int main()
{
while(scanf("%d%d",&n,&k)==2&&(n+k))
{
cnt=0;
rep(i,n-1)
{
int u,v,w;u=read();v=read();w=read();
addEdge(u,v,w);addEdge(v,u,w);
}
printf("%d\n",dfs(1));
rep(i,cnt)head[i]=0;rep(i,n)vis[i]=0;
}
return 0;
}

[日常摸鱼]poj1741Tree-点分治的更多相关文章

  1. [日常摸鱼]Vijos1083小白逛公园-线段树

    题意:单点修改,询问区间最大子段和,$n\leq 5e5$ 考虑分治的方法$O(nlogn)$求一次最大子段和的做法,我们是根据中点分成左右两个区间,那么整个区间的答案要么是左边答案,要么是右边答案, ...

  2. Hash 日常摸鱼笔记

    本篇文章是Hash在信息学竞赛中的应用的学习笔记,分多次更新(已经有很多坑了) 一维递推 首先是Rabin-Karp,对于一个长度为\(m\)的串\(S\) \(f(S)=\sum_{i=1}^{m} ...

  3. [日常摸鱼]HDU1724 Ellipse-自适应Simpson法

    模板题~ QAQ话说Simpson法的原理我还是不太懂-如果有懂的dalao麻烦告诉我~ 题意:每次给一个椭圆的标准方程,求夹在直线$x=l$和$x=r$之间的面积 Simpson法 (好像有时候也被 ...

  4. [日常摸鱼]bzoj1257余数之和

    题意:输入$k,n$,求$\sum_{i=1}^n k \mod i$ $k \mod i=k-i*\lfloor \frac{k}{i} \rfloor $,$n$个$k$直接求和,后面那个东西像比 ...

  5. [日常摸鱼]bzoj1001狼抓兔子-最大流最小割

    题意就是求最小割- 然后我们有这么一个定理(最大流-最小割定理 ): 任何一个网络图的最小割中边的容量之和等于图的最大流. (下面直接简称为最大流和最小割) 证明: 如果最大流>最小割,那把这些 ...

  6. [日常摸鱼]pojKaka's Matrix Travels-拆点+最大费最大流

    方格取数的升级版,每个格子最多取一次. $k=1$的话就是个普及组的dp题,$k=2$就是在之前的基础上多加两维. 然而现在$k$太大了当然就不dp啦 对于$k=1$的情况我们还可以把$(i,j)$向 ...

  7. [日常摸鱼]loj6000「网络流 24 题」搭配飞行员

    题面 应该是二分图匹配,不过我写的是网络最大流. dinic求二分图最大匹配:加个源点和汇点,源点连向二分图的一边所有点,二分图的另一边所有点连向汇点,很明显这样得到的最大流就是这个二分图的最大匹配. ...

  8. [日常摸鱼]bzoj1218[HNOI2003]激光炸弹-二维前缀

    题意:二维网格一些格子有权值,求用边长为$r$的正方形能覆盖到格子权值和的最大值,格子大小$ \leq 5000$ 非常裸的二维前缀,然而 题目下标从0开始! QAQ 要是比赛就要爆零啦- #incl ...

  9. [日常摸鱼]bzoj2724蒲公英-分块

    区间众数经典题~ http://begin.lydsy.com/JudgeOnline/problem.php?id=4839这里可以提交~ 题意大概就是没有修改的询问区间众数,如果有一样的输出最小的 ...

随机推荐

  1. 面试官:别的我不管,这个JVM虚拟机内存模型你必须知道

    前言 说jvm的内存模型前先了解一下物理计算机的内存处理. 物理计算器上用户磁盘和cpu的交互,由于cpu读写速度速度远远大于磁盘的读写速度速度,所以有了内存(高速缓存区).但是随着cpu的发展,内存 ...

  2. 思维导图iMindMap能够对逻辑思维有什么帮助

    思维就像人的身体一样,只有更多的锻炼才能更加灵活,思维导图可以很好的锻炼我们的思维,包括发散思维.图像思维.系统思维.条理性思维.主次思维和空间思维等.快给你的的思维报一个思维导图强化班吧. 为什么导 ...

  3. uniapp兄弟组件如何修改数据?一看就废!

    1. 如A组件里有个num = 10 并需要在生命周期函数created里通过uniapp提供的uni.$on方法来注册全局事件,并加一个形参.( uni.$on( '自定义事件名') , 形参 =& ...

  4. selenium如何处理H5视频

    selenium处理H5视频主要使用的是javascript,javascript函数有内置的对象叫arguments,arguments包含了调用的参数组,[0]代表取第一个值. currentSr ...

  5. PTA天梯赛校内模拟

    最长对称子串 || 区间dp || 马拉车 dp[i][j]表示区间[i, j]是否为回文串,若是则为1,不是则为0. 边界条件: 1. 区间长度为1,dp为1.(奇数个字符递推的起始情况) 2. 区 ...

  6. LeetCode 044 Wildcard Matching

    题目要求:Wildcard Matching Implement wildcard pattern matching with support for '?' and '*'. '?' Matches ...

  7. ASP.NET Core管道详解[6]: ASP.NET Core应用是如何启动的?[下篇]

    要承载一个ASP.NET Core应用,只需要将GenericWebHostService服务注册到承载系统中即可.但GenericWebHostService服务具有针对其他一系列服务的依赖,所以在 ...

  8. 【SHOI2008】JZOJ2020年9月5日提高组 循环的债务

    CSP-2020倒计时:36天 [SHOI2008]JZOJ2020年9月5日提高组 循环的债务 题目 Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有 ...

  9. MySQL重做日志(redo log)

    前面介绍了三种日志:error log.slow log.binlog,这三种都是 Server 层的.今天的 redo log 是 InnoDB引擎专有的日志文件. 为什么要有 redo log 用 ...

  10. moviepy音视频剪辑基类VideoClip的write_gif方法opt、fuzz、dispose、colors、loop等参数的作用

    ☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑模块的视频剪辑基类write_gif方法用于将视频剪辑输出到gif文件,调用语法如下: def write_gif(self, fil ...