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. C语言缓冲区(缓存)详解

    缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区.缓冲区根据其对应的是输入设备还是输出设备,分为输 ...

  2. docfx(二)

    1. 初始化一个docfx项目 1.创建一个文件夹D:\docfx_walkthrough 2.运行cmd 到该文件下执行命令D:\docfx_walkthrough 3.输入命令 docfx ini ...

  3. SQL强化(一)保险业务

    保险业务 : 表结构 : sql语句 : /*1. 根据投保人电话查询出投保人 姓名 身份证号 所有保单 编号 险种 缴费类型*/SELECTt2.cust_name,t2.idcard,t4.pro ...

  4. [图像类名词解释][ RGB YUV HSV相关解释说明]

    一.概述 颜色通常用三个独立的属性来描述,三个独立变量综合作用,自然就构成一个空间坐标,这就是颜色空间.但被描述的颜色对象本身是客观的,不同颜色空间只是从不同的角度去衡量同一个对象.颜色空间按照基本机 ...

  5. Java客户端API

    添加依赖 <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookee ...

  6. 什么是WEBserver? 经常使用的WEBserver有哪些?

    地址:http://www.mamicode.com/ 什么是WEBserver? 经常使用的WEBserver有哪些? 一.什么是WEBserver Webserver能够解析HTTP协议.当Web ...

  7. 从CUMT校园导航出现的问题看CSS布局设计(一) CSS盒模型

    先说说做的这个校园导航系统值得一提的内容: 1. 二级菜单栏  .iframe内嵌窗口(样式设计.用hover做效果) 2. 高德地图API (自定义底图样式.弹跳点.信息窗体.线路导航) 3. DO ...

  8. ubuntu 修复 could not open file '/etc/apt/sources.list'

    问题描述:could not open file '/etc/apt/sources.list' 问题分析:软件源被清空了,也就是 /etc/apt/sources.list 被删除了 解决问题:1. ...

  9. 基础 - 32位操作系统最多只支持4G内存。

    32位操作系统最多只支持4G内存. CPU能不能直接访问硬盘的数据呢, 不能. 只能通过把硬盘的数据先放到内存里, 然后再从内存里访问硬盘的数据.我们平时玩游戏碰上读图loading 进度条的这个过程 ...

  10. 2017-06-21(rmdir mv ln)

    rmdir rmdir  删除空目录 mv mv  剪切或修改命令 mv [原文件或目录] [目标文件]   [原文件与目标文件在同一目录下视为修改,在不同目录下视为剪切] ln ln 链接命令[用于 ...