洛谷 4178 Tree——点分治
题目: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——点分治的更多相关文章
- 洛谷P4178 Tree (点分治)
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...
- 解题:洛谷4178 Tree
题面 重(新)学点分治中...... 普通的点分治一般这几步: 1.找重心 2.从重心开始DFS,得到信息 3.统计经过重心的路径 4.分别分治几棵子树,继续这个过程 然后是常见的(制杖的我的)一些疑 ...
- [洛谷P4178] Tree (点分治模板)
题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...
- 洛谷 P4178 Tree —— 点分治
题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sor ...
- 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)
推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...
- Poj1741/洛谷P4718 Tree(点分治)
题面 有多组数据:Poj 无多组数据:洛谷 题解 点分治板子题,\(calc\)的时候搞一个\(two\ pointers\)扫一下统计答案就行了. #include <cmath> #i ...
- 洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...
- [洛谷P3806] [模板] 点分治1
洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...
- POJ1471 Tree/洛谷P4178 Tree
Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: voi ...
随机推荐
- Boxes and Candies(贪心)
Boxes and Candies Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement Ther ...
- jquery 访问后台方法 并且获取后方法返回的数据
说明: 1.开发环境 asp.net MVC4 c#语言. 后台方法位于控制器中ProController.cs中 后台方法如下: public string GetNumber() { string ...
- CMD命令获取电脑所有连接过的WiFi密码
cmd中输入命令:for /f "skip=9 tokens=1,2 delims=:" %i in ('netsh wlan show profiles') do @echo ...
- 18.Django原生SQL语句查询返回字典
在django中执行自定义语句的时候,返回的结果是一个tuple ,并我不是我所期望的dict.当结果是tuple 时,如果要取得数据,必须知道对应数据在结果集中的序号,用序号的方式去得到值. 如果是 ...
- Hadoop初体验
1.首先准备环境 系统:Linux(centOS) jdk:1.7 这里jdk要安装配置完成,具体步骤参考:Linux环境下安装JDK 注意:本次没有配置免密登录,所以在启动和停止的时候回让你输入多次 ...
- 全栈JavaScript之路( 二十四 )DOM2、DOM3, 不涉及XML命名空间的扩展
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/hatmore/article/details/37658167 (一)DocumentType 类型 ...
- (转)FFMPEG解码H264拼帧简解
http://blog.csdn.net/ikevin/article/details/7649095 H264的I帧通常 0x00 0x00 0x00 0x01 0x67 开始,到下一个帧头开始之前 ...
- ubuntu14.04允许root远程链接、修改主机名
1.设置root密码 sudo passwd root 2.修改主机名 第一步:ubuntu主机名位于/etc/hostname里,将其修改为自己需要的名称. 第二步:修改/etc/hosts文件,将 ...
- cloudera impala编译 安装 配置 启动
无论是采用GDB调试impala或者尝试修改impala源码,前提都是需要本地环境编译impala,这篇文章详细的分享一下impala编译方法以及编译过程遇到的棘手的问题: 前言: impala官方的 ...
- c的详细学习(10)结构体与共用体的学习(二)
在c语言中,结构体数据类型与共用体数据类型都属于构造类型.共用体与结构体数据类型在定义上十分相似,但它们在存储空间的占用分配上有本质的区别.结构体变量是各种类型数据的集合,各成员占据不同的存储空间,而 ...