POJ 1987 Distance Statistics(树的点分治)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
上场CF的C题是一个树的分治。。。
今天刚好又看到一题,就做了下
题意:一棵树,问两个点的距离<=k的点对数目。
http://poj.org/problem?id=1987
貌似是经典的点分治题。。。。。
看成有根树,那么这样的点对路径分为两种,1、过根节点,2、存在于某一棵子树当中。
显然情况2可以看成是一种子情况
对于1的统计,统计所有节点到根节点的距离,枚举+二分可以得到有多少个二元组的和<=k。
但是需要除掉两个点都在某一棵子树中的情况,所以枚举所有子树,同样是枚举+二分。
至于根的选择,选取树的重心。。。我是两次DFS,类似数形DP,求出所有子树的size,找到某一个结点,若删除这个结点,剩下的子树的size中最大的最小。
总体复杂度大概是nlgnlgn
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 40005;
struct Edge{
int v,next,w;
}e[N<<1];
int tot,start[N],n,m,k,del[N],ans=0;
int size[N];
void _add(int u,int v,int w){
e[tot].v=v;e[tot].w=w;
e[tot].next=start[u];start[u]=tot++;
}
void add(int u,int v,int w){
_add(u,v,w);
_add(v,u,w);
}
void cal(int u,int pre){
size[u]=1;
for(int i=start[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(v==pre||del[v]) continue;
cal(v,u);
size[u]+=size[v];
}
}
int newroot,maxsize,totalsize;
void dfs(int u,int pre){
int mx=0,sum=1;
for(int i=start[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(v==pre||del[v]) continue;
dfs(v,u);
mx=max(mx,size[v]);
sum+=size[v];
}
mx=max(mx,totalsize-sum);
if(mx<maxsize){
maxsize=mx;
newroot=u;
}
}
int search(int r){
newroot=-1;maxsize=1<<30;
cal(r,-1);
totalsize=size[r];
dfs(r,-1);
return newroot;
}
int dist[N],idx;
vector<int>sub[N],all;
void gao(int u,int pre){
all.push_back(dist[u]);
sub[idx].push_back(dist[u]);
for(int i=start[u];i!=-1;i=e[i].next){
int v=e[i].v,w=e[i].w;
if(v==pre||del[v]) continue;
dist[v]=dist[u]+w;
gao(v,u);
}
}
void solve(int root){
root=search(root);
del[root]=1;
if(totalsize==1) return ;
idx=0;all.clear();
for(int i=start[root];i!=-1;i=e[i].next){
int v=e[i].v,w=e[i].w;
if(del[v]) continue;
sub[idx].clear();
dist[v]=w;
gao(v,-1);
sort(sub[idx].begin(),sub[idx].end());
idx++;
}
for(int i=0;i<idx;i++){
int pos;
for(int j=0;j<sub[i].size();j++){
pos=upper_bound(sub[i].begin(),sub[i].end(),k-sub[i][j])-sub[i].begin()-1;
if(pos>j) ans-=pos-j;
}
pos=upper_bound(sub[i].begin(),sub[i].end(),k)-sub[i].begin()-1;
if(pos>=0) ans+=pos+1;
}
sort(all.begin(),all.end());
for(int i=0;i<all.size();i++){
int pos=upper_bound(all.begin(),all.end(),k-all[i])-all.begin()-1;
if(pos>i) ans+=pos-i;
}
for(int i=start[root];i!=-1;i=e[i].next){
int v=e[i].v;
if(del[v]) continue;
solve(v);
}
}
int main(){
tot=0;memset(start,-1,sizeof(start));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int u,v,w;char str[5];
scanf("%d%d%d%s",&u,&v,&w,str);
add(u,v,w);
}
scanf("%d",&k);
solve(1);
printf("%d\n",ans);
return 0;
}
POJ 1987 Distance Statistics(树的点分治)的更多相关文章
- POJ 1987 Distance Statistics 树分治
Distance Statistics Description Frustrated at the number of distance queries required to find a ...
- POJ 1987 Distance Statistics
http://poj.org/problem?id=1987 题意:给一棵树,求树上有多少对节点满足距离<=K 思路:点分治,我们考虑把每个距离都存起来,然后排序,一遍扫描计算一下,注意还要减掉 ...
- poj 1741 Tree(树的点分治)
poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...
- POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)
题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream& ...
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- POJ 1741 Tree (树的点分治入门)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 16172 Accepted: 5272 Descripti ...
- POJ 2255 Tree Recovery 树的遍历,分治 难度:0
http://poj.org/problem?id=2255 #include<cstdio> #include <cstring> using namespace std; ...
- POJ 1741/1987 树的点分治
树的点分治,主要思想是每次找子树的重心,计算经过根节点的情况数,再减去点对属于同一子树的情况. #include <iostream> #include <vector> #i ...
- poj 1741 树的点分治(入门)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 18205 Accepted: 5951 Description ...
随机推荐
- ACM—Number Sequence(HDOJ1005)
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005 主要内容: A number sequence is defined as follows: f ...
- [汇编学习笔记][第五章[BX]和loop指令]
第五章[BX]和loop指令 前言 定义描述性符号“()”来表示一个寄存器或一个内存单元的内容,比如: (ax)表示ax中的内容,(al)表示al的内容. 约定符号ideta表示常量. 5.1 [BX ...
- [HeadFist-HTMLCSS学习笔记][第四章Web镇之旅]
重要 访问一个目录,即是访问他的index <a>链接到网站,必须加http:// <a>的title属性,能预先知道链接信息 id属性 使得<a> 能再本地跳转. ...
- (转载)Windows下手动完全卸载Oracle
使用Oracle自带的Universal Installer卸载存在问题: 不干净,不完全,还有一些注册表残留,会影响到后来的安装. 所以,推荐使用手工卸载Oracle. 1.[win+R]-> ...
- canvas写的一个小时钟demo
<!DOCTYPE html> <html> <head> <title>HTML5 Canvas Demo of clock</title> ...
- (转)ubuntu 文件目录结构
文件系统的类型 LINUX有四种基本文件系统类型:普通文件.目录文件.连接文件和特殊文件,可用file命令来识别. 1. 普通文件:如文本文件.C语言元代码.SHELL脚本.二进制的可执行文件等,可用 ...
- stretchlim函数分析
在看imadjust代码时,看到stretchlim函数,特此分析一下,代码注释如下 function lowhigh = stretchlim(varargin) %STRETCHLIM Find ...
- 高性能PHP日志插件--Seaslog
日志系统作为记录系统运行的信息,包括 用户输入,安全日志等,日志系统是不能影响用户的使用. 为什么需要记录日志? 既然日志系统增加了整个系统的开销,为什么我还需要它,这是因为日志能帮我们记录运行的很多 ...
- php+mysql+pdo连接数据库
1.$pdo = new PDO("mysql:host=localhost;dbname=test","root","123456");/ ...
- OER 7451 in Load Indicator : Error Code = OSD-04500:指定了非法选项
alert 日志错误OER 7451 in Load Indicator : Error Code = OSD-04500:指定了非法选项 Sun Apr 22 11:15:51 2012 OER 7 ...