树点分治入门题poj1741

Tree

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 24253   Accepted: 8060

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.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0

Sample Output

8
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=11111;
const int M=55555;
const int INF=1e9;
struct node{
    int v,next,w;
}e[M];
int head[N],tot;
int n,k,vis[N],ans,root,num;
void init(){
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    tot=ans=0;
}
void add(int u,int v,int w){
   e[tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;
}
int mx[N],size[N],mi,dis[N];
void dfssize(int u,int fa){
    size[u]=1;
    mx[u]=0;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa&&!vis[v]) {
            dfssize(v,u);
            size[u]+=size[v];
            if(size[v]>mx[u]) mx[u]=size[v];
        }
    }
}
void dfsroot(int r,int u,int fa){
   if(size[r]-size[u]>mx[u]) mx[u]=size[r]-size[u];
   if(mx[u]<mi) mi=mx[u],root=u;
   for(int i=head[u];~i;i=e[i].next){
    int v=e[i].v;
    if(v!=fa&&!vis[v]) dfsroot(r,v,u);
   }
}
void dfsdis(int u,int d,int fa){
    dis[num++]=d;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa&&!vis[v]) dfsdis(v,d+e[i].w,u);
    }
}
int calc(int u,int d){
   int ret=0;
   num=0;
   dfsdis(u,d,0);
   sort(dis,dis+num);
   int i=0,j=num-1;
   while(i<j){
    while(dis[i]+dis[j]>k&&i<j) --j;
    ret+=j-i;
    ++i;
   }
   return ret;
}
void dfs(int u){//由于每次都取重心,所以最糟糕的情况是logN层,然后每层小于等于N个数遍历,所以复杂度N*logN
    mi=n;
    dfssize(u,0);
    dfsroot(u,u,0);
    ans+=calc(root,0);
    vis[root]=1;
    for(int i=head[root];~i;i=e[i].next){
        int v=e[i].v;
        if(!vis[v]){
         ans-=calc(v,e[i].w);
        dfs(v);
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&k)!=EOF){
        if(!n&&!k) break;
        init();
        int u,v,w;
        for(int i=0;i<n-1;++i) {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        dfs(1);
        printf("%d\n",ans);
    }
}
时间: 2024-08-26 05:55:52

树点分治入门题poj1741的相关文章

COGS 577 蝗灾 [CDQ分治入门题]

题目链接 昨天mhr神犇,讲分治时的CDQ分治的入门题. 题意: 你又一个w*w正方形的田地. 初始时没有蝗虫. 给你两个操作: 1. 1 x y z: (x,y)这个位置多了z只蝗虫. 2. 2 x1 y1 x2 y2: 询问(x1,y1)到(x2,y2)这个矩形内的蝗虫数量. 其中 W<=500000,操作数<=200000 . 题解: w范围太大,无法使用二维数据结构. 于是我们可以分治操作. CDQ分治:定义 solve(l,r) 设m=(l+r)/2; 先计算 l-m 修改操作对 m

HDU 1166 敌兵布阵【树状数组入门题】

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 74051    Accepted Submission(s): 31080 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

poj1741+poj1987+poj2114——点分治入门题集合

最近看了看点分治,从poj上找到几道题,都比较裸.而且感觉这三道题都长得差不多呀qwq ------------------------------------------------ [poj 1741]Tree 题意:给定一棵边带权的树,求两点之间的距离小于或等于K的点对个数. 找重心,相当于把无根树转变为有根树.再利用分治的思想(根据经过重心或不经过重心来划分). 对于在同一个子树的情况要单独拎出来算并减去它们(因为是不该算在内的呀qwq) 另外选取重心的好处是时间复杂度O(NlogN*l

没有上司的舞会——树状DP 入门题,真的比想象中简单许多

本来线性DP 都不怎么有信心,可以说学得非常差,于是下意识地觉得树状的肯定超过了我的理解能力,然后做这题的时候就直接翻了题解,哪知道这么简单……简直比01 背包还好理解啊,看来以后不能总是看到算法标签就退避了. 1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 using namespace std; 5 const int N=10086; 6 int n,val[N]; 7 int f[N][4

POJ-3667 线段树区间合并入门题

题意:长度为n的区间,m个操作,一开始都是0 1 x表示求出长度为x的0的连续区间的最左端,并把这个区间变成1 2 x y表示将区间[x,y]变成0 线段树的区间合并第一题: 每次维护左端连续区间长度ls.右端连续区间长度rs,最大连续长度ms 区间合并的注意点主要在push up操作: 每次更新了一段区间之后向上更新,首先,父区间的ls继承左子树的ls,父区间的rs继承右子树的rs 然后就是重点:左右区间合并之后中间部分可能是连续的!!! 所以:如果整个左.右子区间都是“满的”,父区间的ls和

poj2299 树状数组入门题

题意:利用树状数组求逆序数: 思路:因为输入范围较大,先离散化一下,得到的数组a记录了原来数组的大小关系:然后按下标顺序执行add(a[i],1),这样sum(a[i])得到的就是小于等于a[i]的个数,i-sum(a[i])即为a[i]前面比a[i]大的数的个数 //外循环n次并累加i-sum(a[i])得到逆序数 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<alg

spoj375 Query on a tree(树链剖分入门题)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int MAXN=10010

二维树状数组入门题 poj2642Stars

题目连接:Stars 题解:把一维的的树状数组扩展到二维就行,复杂度为o(mlog^2n) #include<bits/stdc++.h> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #include<algorithm> #define pb pus

POJ 2486 树型dp 入门题

从根走k步获得的最大权值. 感觉情况不容易弄全.而步数从大到小有种背包的感觉. #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> #include <iostream> #include <cstdlib> #include <string> #include <vect