题目:https://www.luogu.org/problemnew/show/P4178

点分治。如果把每次的 dis 和 K-dis 都离散化,用树状数组找,是O(n*logn*logn),会T7个点。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=4e4+;
int n,hd[N],xnt,to[N<<],nxt[N<<],w[N<<],f[N<<],siz[N],ans,mn,rt;
ll dis[N],tis[N],tp[N<<],tnt,K;
bool vis[N],sj[N];
void add(int x,int y,ll z)
{
to[++xnt]=y;nxt[xnt]=hd[x];w[xnt]=z;hd[x]=xnt;
to[++xnt]=x;nxt[xnt]=hd[y];w[xnt]=z;hd[y]=xnt;
}
void getrt(int cr,int fa,int s)
{
siz[cr]=;int mx=;
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)
{
getrt(v,cr,s);siz[cr]+=siz[v];mx=max(mx,siz[v]);
}
mx=max(mx,s-siz[cr]);
if(mx<mn)mn=mx,rt=cr;
}
void add(int x){for(;x<=tnt;x+=(x&-x))f[x]++;}
int query(int x){int ret=;for(;x;x-=(x&-x))ret+=f[x];return ret;}
void dfs(int cr,int fa,ll lj)
{
dis[cr]=lj;sj[cr]=;
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)
dfs(v,cr,lj+w[i]);
}
int calc(int cr,ll w)
{
memset(sj,,sizeof sj);tnt=;dfs(cr,,w);
for(int i=;i<=n;i++) if(sj[i]&&dis[i]<=K)
{
tis[i]=K-dis[i];tp[++tnt]=dis[i];tp[++tnt]=tis[i];
// printf("dis[%d]=%lld tis[%d]=%lld\n",i,dis[i],i,tis[i]);
}
sort(tp+,tp+tnt+);tnt=unique(tp+,tp+tnt+)-tp-;
int ret=;
for(int i=;i<=n;i++) if(sj[i]&&dis[i]<=K)
{
dis[i]=lower_bound(tp+,tp+tnt+,dis[i])-tp;
tis[i]=lower_bound(tp+,tp+tnt+,tis[i])-tp;
// printf("dis[%d]=%lld tis[%d]=%lld\n",i,dis[i],i,tis[i]);
ret+=query(tis[i]);add(dis[i]);
}
memset(f,,sizeof f);
return ret;
}
void solve(int cr,int s)
{
// printf("rt=%d\n",cr);
vis[cr]=;
ans+=calc(cr,);
// printf("cr=%d ans=%d\n",cr,ans);
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]])
{
ans-=calc(v,w[i]);
int ts=(siz[cr]>siz[v]?siz[v]:s-siz[cr]);//-siz[cr]!!!
mn=N;getrt(v,,ts);solve(rt,ts);
}
}
int main()
{
scanf("%d",&n);int x,y;ll z;
for(int i=;i<n;i++)
{
scanf("%d%d%lld",&x,&y,&z);add(x,y,z);
}
scanf("%lld",&K);
mn=N;getrt(,,n);solve(rt,n);
printf("%d\n",ans);
return ;
}

应当排序后枚举两个指针。(代码中两种方法时间一样)

如果把 ts=s-siz[cr] 写成 ts=s-siz[v] ,就会T7个点(?)!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=4e4+;
int n,hd[N],xnt,to[N<<],nxt[N<<],w[N<<],siz[N],mn,rt,sta[N],top,K,ans;
bool vis[N];
void add(int x,int y,int z)
{
to[++xnt]=y;nxt[xnt]=hd[x];w[xnt]=z;hd[x]=xnt;
to[++xnt]=x;nxt[xnt]=hd[y];w[xnt]=z;hd[y]=xnt;
}
void getrt(int cr,int fa,int s)
{
siz[cr]=;int mx=;
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)
{
getrt(v,cr,s);siz[cr]+=siz[v];mx=max(mx,siz[v]);
}
mx=max(mx,s-siz[cr]);
if(mx<mn)mn=mx,rt=cr;
}
void dfs(int cr,int fa,int lj)
{
sta[++top]=lj;
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)
dfs(v,cr,lj+w[i]);
}
int calc(int cr,int w)
{
int ret=;dfs(cr,,w);
// l=1;r=0;
// sort(sta+l,sta+r+1);
// while(l<=r)
// if(sta[l]+sta[r]<=K)ret+=r-l,l++;
// else r--;
sort(sta+,sta+top+);int p=top;
for(int i=;i<=top;i++)
{
while(sta[p]+sta[i]>K&&p)p--;if(!p)break;
ret+=p-(p>=i);
}
top=;
// printf("cr=%d ret=%d\n",cr,ret);
return ret>>;
}
void solve(int cr,int s)
{
// printf("rt=%d\n",cr);
vis[cr]=;
ans+=calc(cr,);
// printf("cr=%d ans=%d\n",cr,ans);
for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]])
{
ans-=calc(v,w[i]);
int ts=(siz[cr]>siz[v]?siz[v]:s-siz[cr]);//s-siz[cr]!!!
mn=N;getrt(v,,ts);solve(rt,ts);
}
}
int main()
{
scanf("%d",&n);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);add(x,y,z);
}
scanf("%d",&K);
mn=N;getrt(,,n);solve(rt,n);
printf("%d\n",ans);
return ;
}

洛谷 4178 Tree——点分治的更多相关文章

  1. 洛谷P4178 Tree (点分治)

    题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式:   N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...

  2. 解题:洛谷4178 Tree

    题面 重(新)学点分治中...... 普通的点分治一般这几步: 1.找重心 2.从重心开始DFS,得到信息 3.统计经过重心的路径 4.分别分治几棵子树,继续这个过程 然后是常见的(制杖的我的)一些疑 ...

  3. [洛谷P4178] Tree (点分治模板)

    题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...

  4. 洛谷 P4178 Tree —— 点分治

    题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sor ...

  5. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  6. Poj1741/洛谷P4718 Tree(点分治)

    题面 有多组数据:Poj 无多组数据:洛谷 题解 点分治板子题,\(calc\)的时候搞一个\(two\ pointers\)扫一下统计答案就行了. #include <cmath> #i ...

  7. 洛谷P3810 陌上花开 CDQ分治(三维偏序)

    好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...

  8. [洛谷P3806] [模板] 点分治1

    洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...

  9. POJ1471 Tree/洛谷P4178 Tree

    Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: voi ...

随机推荐

  1. EasyNVR完美搭配腾讯云CDN/阿里云CDN进行RTMP、HLS直播加速的使用说明

    1.相关资料入口 腾讯云LVB EasyNVR.com 2.加速说明 2.1. 腾讯LVB加速 2.1.1. 开通服务 腾讯云视频LVB开通入口 2.1.2. 登录进入控制台 腾讯云直播控制台 2.1 ...

  2. 【python】-- 模块、os、sys、time/datetime、random、logging、re

    模块 模块,用一堆代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个 ...

  3. 【python】-- 事件驱动介绍、阻塞IO, 非阻塞IO, 同步IO,异步IO介绍

    事件驱动介绍 一.前言 通常,我们写服务器处理模型的程序时,有以下几种模型: (1)每收到一个请求,创建一个新的进程,来处理该请求: (2)每收到一个请求,创建一个新的线程,来处理该请求: (3)每收 ...

  4. 【网络与系统安全】20179209 wireshark和nmap实验

    TCP三次握手包 在进行实验前,先梳理一遍TCP三次握手的过程,这个图是我本科学网络时画过不少于十遍的图,我觉得非常有纪念意义. 稍作解释,第一次握手,客户端发起请求连接,发送一个标志位为SYN的ip ...

  5. Django 之 缓存机制

    Django 缓存机制 缓存介绍 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次 ...

  6. (转)Web Service和WCF的到底有什么区别

    [1]Web Service:严格来说是行业标准,也就是Web Service 规范,也称作WS-*规范,既不是框架,也不是技术. 它有一套完成的规范体系标准,而且在持续不断的更新完善中. 它使用XM ...

  7. requests ip代理池单ip和多ip设置方式

    reqeusts库,在使用ip代理时,单ip代理和多ip代理的写法不同 (目前测试通过,如有错误,请评论指正) 单ip代理模式 省去headers等 import requests proxy = { ...

  8. Please enable network time synchronisation in system settings

    eth区块同步出现这样的WARN: WARN [06-17|13:02:42] System clock seems off by -51.509894715s, which can prevent ...

  9. shell单例-处理方案

    shell单例:当某一个shell脚本需要重复执行时(shell定时任务 etc),为了避免多个相同任务之间交叉,造成数据的混乱或者错误,需要脚本单例执行. 就是前一个进程执行时,后一个进程需要阻塞等 ...

  10. 《python基础教程(第二版)》学习笔记 字符串(第3章)

    <python基础教程(第二版)>学习笔记 字符串(第3章)所有的基本的序列操作(索引,分片,乘法,判断成员资格,求长度,求最大最小值)对字符串也适用.字符串是不可以改变的:格式化输出字符 ...