Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 20098   Accepted: 6608

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
Define dist(u,v)=The min distance between node u and v. 
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
Write a program that will count how many pairs which are valid for a given tree. 

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
The last test case is followed by two zeros. 

Output

For each test case output the answer on a single line.

题意:给一颗带权树,求树上长度不超过L的路径条数

首先有一个有树高限制时的树形DP做法..........
 

对于一条树路径 只有经过或不经过一个点的情况

考虑经过一个点的路径,可以由其他点到它的两条路径拼出来

对于不经过的情况 把一棵树按这个点拆成好几棵分治
 
每次对于当前子树选择树的重心,最多递归logn次,而每层最多只有n个点(每层的所有子树组成整棵树),复杂度O(logn*处理每层的复杂度)
 
过程:
1.求重心
2.处理经过当前点的路径
3.对子树分治
 
每次分治的各个子树是互不影响的,vis[i]表示i这个点已经分治过了
 
注意:既然你的写法是先找重心在递归,那么一定要rt=0;dfsRt(v,0);dfsSol(rt);是rt啊啊啊啊啊不是v了
 
对于本题,处理经过点u的路径时,先dfs子树中所有点对深度,排序两个指针往里扫计算<=L的,在减去在同一颗子树里的(同样计算)
总复杂度O(nlog^2n)
 
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=,INF=1e9+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,L,u,v,w;
struct edge{
int v,w,ne;
}e[N<<];
int h[N],cnt;
inline void ins(int u,int v,int w){
cnt++;
e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
} int size[N],d[N],vis[N],root,sum;
void dfsRoot(int u,int fa){
size[u]=;d[u]=;
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]||v==fa) continue;
dfsRoot(v,u);
size[u]+=size[v];
d[u]=max(d[u],size[v]);
}
d[u]=max(d[u],sum-size[u]);
if(d[u]<d[root]) root=u;
}
int deep[N],a[N];
void dfsDeep(int u,int fa){
a[++a[]]=deep[u];
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]||v==fa) continue;
deep[v]=deep[u]+e[i].w;
dfsDeep(v,u);
}
} int cal(int u,int now){
deep[u]=now;a[]=;
dfsDeep(u,);
sort(a+,a++a[]);
int l=,r=a[],ans=;
while(l<r){
if(a[l]+a[r]<=L) ans+=r-l,l++;
else r--;
}
return ans;
}
int ans;
void dfsSol(int u){//printf("dfs %d\n",u);
vis[u]=;
ans+=cal(u,);
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]) continue;
ans-=cal(v,e[i].w);
sum=size[v];
root=;dfsRoot(v,);
dfsSol(root);
}
} int main(){
//freopen("in.txt","r",stdin);
while(true){
n=read();L=read();if(n==) break;
cnt=;memset(h,,sizeof(h));
memset(vis,,sizeof(vis));
ans=;
for(int i=;i<=n-;i++) u=read(),v=read(),w=read(),ins(u,v,w);
sum=n;
root=;d[]=INF;
dfsRoot(,);
dfsSol(root);
printf("%d\n",ans);
}
}
 还有一种做法,用treap维护,考虑经过每个点的路径时,建一颗treap维护长度,每个点加上之前遍历过的这点的子树中<L-deep[v]+1的,最后再把这棵子树的所有深度加入treap
 

//
// main.cpp
// treap
//
// Created by Candy on 2017/1/9.
// Copyright ? 2017年 Candy. All rights reserved.
// #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lc t[x].l
#define rc t[x].r
const int N=1e5+,INF=1e9;
int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
} struct node{
int l,r,v,w,size,rnd;
}t[N];
int sz,root;
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline void lturn(int &x){
int c=rc;rc=t[c].l;t[c].l=x;
t[c].size=t[x].size;update(x);x=c;
}
inline void rturn(int &x){
int c=lc;lc=t[c].r;t[c].r=x;
t[c].size=t[x].size;update(x);x=c;
}
void ins(int &x,int v){
if(x==){
x=++sz;
t[x].l=t[x].r=;
t[x].v=v;t[x].w=t[x].size=;
t[x].rnd=rand();
return;
}
t[x].size++;
if(v==t[x].v) t[x].w++;
else if(v<t[x].v){
ins(lc,v);
if(t[lc].rnd<t[x].rnd) rturn(x);
}else{
ins(rc,v);
if(t[rc].rnd<t[x].rnd) lturn(x);
}
}
int que(int x,int v){//cnt of <v
if(!x) return ;
if(t[x].v==v) return t[lc].size;
if(v<t[x].v) return que(lc,v);
else return t[lc].size+t[x].w+que(rc,v);
} int n,L,u,v,w;
struct edge{
int v,w,ne;
}e[N<<];
int h[N],cnt;
inline void ins(int u,int v,int w){
cnt++;
e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
}
int vis[N],size[N],f[N],sum,rt;
void dfsRoot(int u,int fa){
size[u]=;f[u]=;
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]||v==fa) continue;
dfsRoot(v,u);
size[u]+=size[v];
f[u]=max(f[u],size[v]);
}
f[u]=max(f[u],sum-size[u]);
if(f[u]<f[rt]) rt=u;
} int ans,deep[N];
void dfsDeep(int u,int fa,int p){
if(p==) ans+=que(root,L-deep[u]+);
else ins(root,deep[u]);
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]||v==fa) continue;
deep[v]=deep[u]+e[i].w;
dfsDeep(v,u,p);
}
}
void dfsSol(int u){//printf("sol %d\n",u);
vis[u]=;
sz=root=;
ins(root,);
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]) continue;
deep[v]=e[i].w;
dfsDeep(v,u,);
dfsDeep(v,u,);
}
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(vis[v]) continue;
sum=size[v];
rt=;dfsRoot(v,u);
dfsSol(rt);
}
}
int main(){
//freopen("in.txt","r",stdin);
while(true){
n=read();L=read();if(n==) break;
cnt=;memset(h,,sizeof(h));
memset(vis,,sizeof(vis));
ans=;
for(int i=;i<=n-;i++) u=read(),v=read(),w=read(),ins(u,v,w);
sum=n;
rt=;f[]=INF;
dfsRoot(,);
dfsSol(rt);
printf("%d\n",ans);
}
}
 
 

POJ1741Tree [点分治]【学习笔记】的更多相关文章

  1. 点分治&&动态点分治学习笔记

    突然发现网上关于点分和动态点分的教程好像很少……蒟蒻开篇blog记录一下吧……因为这是个大傻逼,可能有很多地方写错,欢迎在下面提出 参考文献:https://www.cnblogs.com/LadyL ...

  2. 初学cdq分治学习笔记(可能有第二次的学习笔记)

    前言骚话 本人蒟蒻,一开始看到模板题就非常的懵逼,链接,学到后面就越来越清楚了. 吐槽,cdq,超短裙分治....(尴尬) 正片开始 思想 和普通的分治,还是分而治之,但是有一点不一样的是一般的分治在 ...

  3. CDQ分治学习笔记

    数据结构中的一块内容:$CDQ$分治算法. $CDQ$显然是一个人的名字,陈丹琪(NOI2008金牌女选手) 这种离线分治算法被算法界称为"cdq分治" 我们知道,一个动态的问题一 ...

  4. [摸鱼]cdq分治 && 学习笔记

    待我玩会游戏整理下思绪(分明是想摸鱼 cdq分治是一种用于降维和处理对不同子区间有贡献的离线分治算法 对于常见的操作查询题目而言,时间总是有序的,而cdq分治则是耗费\(O(logq)\)的代价使动态 ...

  5. CDQ分治学习笔记(三维偏序题解)

    首先肯定是要膜拜CDQ大佬的. 题目背景 这是一道模板题 可以使用bitset,CDQ分治,K-DTree等方式解决. 题目描述 有 nn 个元素,第 ii 个元素有 a_iai​.b_ibi​.c_ ...

  6. [Updating]点分治学习笔记

    Upd \(2020/2/15\),又补了一题 LuoguP2664 树上游戏 \(2020/2/14\),补了一道例题 LuoguP3085 [USACO13OPEN]阴和阳Yin and Yang ...

  7. 三维偏序[cdq分治学习笔记]

    三维偏序 就是让第一维有序 然后归并+树状数组求两维 cdq+cdq不会 告辞 #include <bits/stdc++.h> // #define int long long #def ...

  8. 学习笔记 | CDQ分治

    目录 前言 啥是CDQ啊(它的基本思想) 例题 后记 参考博文 前言 博主太菜了 学习快一年的OI了 好像没有什么会的算法 更寒碜的是 学一样还不精一样TAT 如有什么错误请各位路过的大佬指出啊感谢! ...

  9. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  10. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

随机推荐

  1. 独立成分分析(ICA)的模拟实验(R语言)

    本笔记是ESL14.7节图14.42的模拟过程.第一部分将以ProDenICA法为例试图介绍ICA的整个计算过程:第二部分将比较ProDenICA.FastICA以及KernelICA这种方法,试图重 ...

  2. [国嵌攻略][149][Yaffs2文件系统应用]

    嵌入式系统自启动 MTD技术通过把Nand FLash划分成bootloader分区,Linux kernel分区和file system分区来达到自启动的效果. 配置和编译内核 1.配置Linux内 ...

  3. [学习OpenCV攻略][012][读取、修改、保存图像]

    使用 imread 读取图像,图像路径为 imageName ,图像按BGR格式读取. image = imread( imageName, CV_LOAD_IMAGE_COLOR); 将RGB图像转 ...

  4. 《JavaScript设计模式与开发实践》知识点笔记

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC" } p.p2 { margin: 0.0px ...

  5. MVC编程实例----简易电子商务网站(一)

    一.总体概览.规划 本文将会创建一个基本的电子商务网站.由于电子商务网站的基本功能都是差不多的,此处省去了需求分析等工作,直接总结出结论.分为4个基本功能: 商品浏览 会员功能 购物车 订单结账 其中 ...

  6. 【编程技巧】addSubview和insertSubview的区别

    addSubview 是将view加到所有层的最顶层 相当于将insertSubview的atIndex参数设置成view.subviews count 即 [view addSubview:onev ...

  7. python与MySQL

    一.python与mysql交互 因版本不同python操作mysql有两个模块,python3不再支持MySQL-python,模块使用都一样: python2.7:MySQL-python pyt ...

  8. C# 内置 DateTime类详解

    C# 内置 DateTime类详解 摘抄自微软官方文档,用来方便自己查阅:网址:https://msdn.microsoft.com/zh-cn/library/system.datetime(v=v ...

  9. winform程序压缩文件上传,服务器端asp.net mvc进行接收解压

    期间编程没什么难度,唯一可能忽略导致结果失败是asp.net  mvc配置 对于压缩文件大的话,需要配置mvc的最大接收量: <system.web> <httpRuntime ma ...

  10. mysql根据汉字首字母排序[转]

    select  areaName  from area order by   convert(areaName USING gbk)   COLLATE   gbk_chinese_ci asc 说明 ...