POJ1741:Tree
浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html
题目传送门:http://poj.org/problem?id=1741
这是一道树分治的模板题。
我们考虑当前经过联通块的重心\(rt\)的路径小于等于\(k\)的有多少条,不经过\(rt\)的等把\(rt\)这个点删了之后再递归去统计。
我们可以记录一下从\(rt\)出发到每个点的距离\(dis\),然后把\(dis\)从小到大排序,用两个指针\(l\)和\(r\)分别指向\(dis\)数组的开头和结尾。每次以\(l\)为基准,找能与\(l\)匹配起来小于等于\(k\)的另一条路径。假设\(l\)的\(dis\)加上\(r\)的\(dis\)小于等于\(k\),且\(r\)是满足这个条件的最长的路径,那么区间\([l,r]\)里的所有\(dis\)加上\(l\)的\(dis\)都会小于等于\(k\)。所以对于\(l\),能与它匹配的路径条数是\(r-l+1-num\),\(num\)表示区间\([l,r]\)中与\(l\)在同一个子树里的路径条数,这个我们可以开个桶动态维护。然后对于\(l\)不断增加,\(r\)必然是递减的,所以复杂度是\(O(n)\)的。因为每个点只会被递归\(log\)次,所以总复杂度是\(O(nlog^2n)\)的。
边分治做法差不太多,不过空间会因为要重建树而翻一倍。
时间复杂度:\(O(nlog^2n)\)
空间复杂度:\(O(n)\)
点分治版代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e4+5;
bool vis[maxn];
int siz[maxn],num[maxn];
int n,limit,tot,ans,mx,rt,cnt,N;
int now[maxn],son[maxn*2],pre[maxn*2],val[maxn*2];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct road {
int bel,dis;
road() {}
road(int _bel,int _dis) {
bel=_bel,dis=_dis;
}
bool operator<(const road &a)const {
return dis<a.dis;
}
}tmp[maxn];
void add(int a,int b,int c) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b,val[tot]=c;
}
void clear() {
ans=tot=0;
memset(now,0,sizeof(now));
memset(vis,0,sizeof(vis));
}
void find_root(int fa,int u) {
int res=0;siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)
find_root(u,v),siz[u]+=siz[v],res=max(res,siz[v]);
res=max(res,N-siz[u]);
if(res<mx)mx=res,rt=u;
}
void solve(int belong,int fa,int u,int dis) {
tmp[++cnt]=road(belong,dis);siz[u]=1;//之前求出的siz是以u为根的,现在顺便把以rt为根时的siz求出来,递归下去就直接可以调用了。
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)
solve(belong,u,v,dis+val[p]),siz[u]+=siz[v];
}
void point_division(int u,int size) {//size表示当前联通块总大小
N=size,mx=rt=n+1,find_root(0,u);
u=rt,cnt=0,num[0]=1,vis[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v])solve(v,u,v,val[p]),num[v]=siz[v];
sort(tmp+1,tmp+cnt+1);int l=0,r=cnt;
while(l<r) {
while(r>l&&tmp[l].dis+tmp[r].dis>limit)num[tmp[r].bel]--,r--;
if(l<r)ans+=(r-l+1)-num[tmp[l].bel];num[tmp[l].bel]--,l++;
}
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v])point_division(v,siz[v]);
}
int main() {
while(1) {
n=read(),limit=read();
if(!n)break; clear();
for(int i=1;i<n;i++) {
int x=read(),y=read(),v=read();
add(x,y,v),add(y,x,v);
}
point_division(1,n);
printf("%d\n",ans);
}
return 0;
}
边分治版代码如下:
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef pair<int,int> pii;
#define fr first
#define sc second
const int maxn=2e4+5;
bool vis[maxn];
int siz[maxn],num[maxn];
int n,limit,tot=1,ans,mx,id,cnt,N;
int now[maxn],pre[maxn*2],son[maxn*2],val[maxn*2];
vector<pii>to[maxn];
vector<pii>::iterator it;
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct road {
int bel,dis;
road() {}
road(int _bel,int _dis) {
bel=_bel,dis=_dis;
}
bool operator<(const road &a)const {
return dis<a.dis;
}
}tmp[maxn];
void clear() {
tot=ans=0;
memset(vis,0,sizeof(vis));
memset(now,0,sizeof(now));
}
void add(int a,int b,int c) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b,val[tot]=c;
}
void find_son(int fa,int u) {
to[u].clear();
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(v!=fa)to[u].push_back(make_pair(v,val[p])),find_son(u,v);
}
void rebuild() {
tot=1,memset(now,0,sizeof(now));
for(int i=1;i<=cnt;i++) {
int size=to[i].size();
if(size<=2) {
for(it=to[i].begin();it!=to[i].end();it++) {
pii tmp=*it;
add(i,tmp.fr,tmp.sc),add(tmp.fr,i,tmp.sc);
}
}
else {
pii u1=make_pair(++cnt,0),u2;
if(size==3)u2=to[i].front();else u2=make_pair(++cnt,0);
add(i,u1.fr,u1.sc),add(u1.fr,i,u1.sc);
add(i,u2.fr,u2.sc),add(u2.fr,i,u2.sc);
if(size>3) {
to[cnt-1].clear();to[cnt].clear();int tmp=0;
for(it=to[i].begin();it!=to[i].end();it++) {
if(!tmp)to[cnt].push_back(*it);
else to[cnt-1].push_back(*it);tmp^=1;
}
}
else {
to[cnt].clear();
for(int j=1;j<=2;j++)
to[cnt].push_back(to[i].back()),to[i].pop_back();
}
}
}
}
void find_edge(int fa,int u) {
siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[p>>1]&&v!=fa) {
find_edge(u,v),siz[u]+=siz[v];
if(abs(N-2*siz[v])<mx)mx=abs(N-2*siz[v]),id=p>>1;
}
}
void solve(int bel,int fa,int u,int dis) {
if(u<=n)tmp[++tot]=road(bel,dis),num[bel]++;siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[p>>1]&&v!=fa)solve(bel,u,v,dis+val[p]),siz[u]+=siz[v];
}
void work(int u,int size) {
N=size,mx=id=cnt+1,find_edge(0,u);
tot=0,vis[id]=1;if(id==cnt+1)return;
int u1=son[id<<1],u2=son[id<<1|1];
num[u1]=num[u2]=0;
solve(u1,0,u1,0),solve(u2,0,u2,0);
sort(tmp+1,tmp+tot+1);int l=1,r=tot;
while(l<r) {
while(r>l&&tmp[r].dis+tmp[l].dis>limit-val[id<<1])num[tmp[r].bel]--,r--;
if(l<r)ans+=(r-l+1)-num[tmp[l].bel];num[tmp[l].bel]--,l++;
}
work(u1,siz[u1]),work(u2,siz[u2]);
}
int main() {
while(1) {
cnt=n=read();limit=read();
if(!n)break; clear();
for(int i=1;i<n;i++) {
int x=read(),y=read(),v=read();
add(x,y,v),add(y,x,v);
}
find_son(0,1);rebuild();
work(1,cnt);printf("%d\n",ans);
}
return 0;
}
POJ1741:Tree的更多相关文章
- POJ1741:Tree——题解+树分治简要讲解
http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. ———————————————————— 以这道题为例记录一下对于树分治的理解. 树 ...
- 【POJ1741】Tree(点分治)
[POJ1741]Tree(点分治) 题面 Vjudge 题目大意: 求树中距离小于\(K\)的点对的数量 题解 完全不觉得点分治了.. 简直\(GG\),更别说动态点分治了... 于是来复习一下. ...
- codeforces 375D:Tree and Queries
Description You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. ...
- POJ 3237:Tree(树链剖分)
http://poj.org/problem?id=3237 题意:树链剖分.操作有三种:改变一条边的边权,将 a 到 b 的每条边的边权都翻转(即 w[i] = -w[i]),询问 a 到 b 的最 ...
- leetcode题解:Tree Level Order Traversal II (二叉树的层序遍历 2)
题目: Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from ...
- 命令行打印文件树列表: tree
Linux & Mac 1.下载tree lib //mac brew install tree //centos yum install tree //ubuntu apt-get inst ...
- Linux:tree命令详解
tree 以树状图列出目录的内容 语法 tree(选项)(参数) 选项 -a:显示所有文件和目录: -A:使用ASNI绘图字符显示树状图而非以ASCII字符组合: -C:在文件和目录清单加上色彩,便于 ...
- TYOI Day1 travel:Tree dp【处理重复走边】
题意: 给你一棵树,n个节点,每条边有长度. 然后有q组询问(u,k),每次问你:从节点u出发,走到某个节点的距离mod k的最大值. 题解: 对于无根树上的dp,一般都是先转成以1为根的有根树,然后 ...
- linux命令学习笔记(61):tree 命令
shendu@shenlan:~$ tree 程序“tree”尚未安装. 您可以使用以下命令安装: sudo apt-get install tree shendu@shenlan:~$ sudo a ...
随机推荐
- crtmp Server 开启rtsp服务功能
Crtmp Server 包含了rtsp 服务功能,如果需要一个简单轻量的rtsp服务,Crtmp Server会是不错的选择. 默认情况下,rtsp功能是关闭的,需要在配置文件中打开.window环 ...
- Python+Selenium框架unittest执行脚本方法之discover()方法
继续接着介绍,如何利用unittest管理和执行测试用例的问题,这里我们还是利用之前已经有的三条测试用例,如果你跳过了前面文章,请回到框架设计篇的第八篇和第七篇,里面有相关测试类的文件.本文来介绍,如 ...
- python 调用函数时使用星号 *, **
python 调用函数时使用星号 *, ** 调用函数时使用星号 * 或 ** test(*args):* 的作用其实就是把序列 args 中的每个元素,当作位置参数传进去.如果 args 等于 (1 ...
- 2016年第七届蓝桥杯c/c++省赛B组
2016年第七届蓝桥杯c/c++省赛B组 声明:以下答案是我自己做的.不能保证正确,须要參考正确答案的请到其它地方找. 第一题 :煤球数目 题目叙述: 有一堆煤球,堆成三角棱锥形.详细: 第一层放1个 ...
- hdu5387(2015多校8)--Clock(模拟)
题目链接:点击打开链接 题目大意:给出一个时间,问在钟表上这个时间的时候.时针和分针的角度,时针和秒针的角度.分针和秒针的角度.假设不是整数以分数的形式输出. 假设依照最小的格来算,那么: 1s对于秒 ...
- 关于 angular cookie 设置的坑
初识Angular,才知道掉进了这么一个各种大坑的坑. 先说下对于$cookie.put 这几个方法,只有1.4以上版本才可以用,其余低于版本请使用 $cookieStore: 下面举例下使用方法: ...
- inception安装步骤---自己整理的安装步骤
inception安装步骤---自己整理的安装步骤2015-09-18 15:51 6185人阅读 评论(1) 收藏 举报 分类: inception相关版权声明:本文为博主原创文章,未经博主允许不得 ...
- Linux机器间ssh免密登录
前言 一台Linux机器通过ssh的方式连接别的机器或通过scp的方式传输文件,都需要输入密码. 为了解决每次输入密码的困扰,可采用添加密钥的方式实现. 实现过程 源服务器A,目标服务器B. 1.在源 ...
- unity 接触一个月的感受和心得
unity scrollview 遇到的问题 一个scrollview作为翻页,这样的效果调整. 一页上面有三个scrollview,这三个scrollview上的items不受下层整个页面的scro ...
- asp.net mvc4 修改密码界面
1.效果 说明:1.界面不太美观 这里面主要是包括 利用jQuery 插件validate验证form字段,jQuery提交form表单的方式 1.HTML代码 <!DOCTYPE html&g ...