洛谷 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 ...
随机推荐
- vmware 下的三种网络模式
VMWare提供三种工作模式桥接(bridge).NAT(网络地址转换)和host-only(主机模式). 桥接模式 在桥接模式下,VMWare虚拟出来的操作系统就像是局域网中的一台独立的主机(主机和 ...
- 探测web服务器质量——pycurl
pycurl是一个用C语言写的libcurl Python实现,功能非常强大,支持的操作协议有FTP.HTTP.HTTPS.TELNET等,可以理解为Linux下curl命令功能的Python封装,简 ...
- Java编程思想(第4版) 中文清晰PDF完整版
Java编程思想(第4版) 中文清晰PDF完整版 [日期:2014-08-11] 来源:Linux社区 作者:Linux [字体:大 中 小] <Java编程思想>这本书赢得了全 ...
- 【LeetCode】:二叉搜索树
相关概念: 一棵二叉搜索树(BST)是以一棵二叉树来组织的,可以用链表数据结构来表示,其中,每一个结点就是一个对象,一般地,包含数据内容key和指向孩子(也可能是父母)的指针属性.如果某个孩子结点不存 ...
- vim编辑器常规配置
为了很舒服的编写程序,请把vim配置好 # apt install vim 安装vim编辑器 #sudo vim /etc/vim/vimrc ///必须加上权限sudo 在这个文件中,会有 ...
- 简单做出HTML5翻页效果文字特效
之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...
- pulseaudio备注
参考http://www.ubuntu-tw.org/modules/newbb/viewtopic.php?viewmode=compact&topic_id=10102 Ubuntu 8. ...
- nginx别名配置,状态配置,include优化
一.nginx帮助参数 下面是关于/application/nginx/sbin/nginx 的参数帮助 [root@A conf]# /application/nginx/sbin/nginx -h ...
- Docker 搭建本地Registry
Docker已经将Registry开源,Registry本身也是一个容器. 1. 修改配置/etc/docker/daemon.json,去掉docker默认的https的访问 里面的内容是一个j ...
- Centos安装ntfs
ntfs优盘插在Linux上是无法直接使用的,需要安装ntfs插件才可使用 centos上安装ntfs-3g 下载ntfs-3g安装包,上传至需要安装的服务器并解压 cd 进入ntfs-3g目录,依次 ...