大概思路:树点分治,重心树中每个重心维护一个总的平衡树,树中保存属于该重心的点到该重心的距离,然后对于去掉该重心后形成的子树分别再保存一份。

用这种方式实现的话,还可以支持修改与多次查询,每次操作都是O(logn*logn)

感悟:

点分治正如一个前辈说的,是“借助”重心的力量,来维护与查询与某点距离相关的问题,我们知道点u到它各个重心的距离关系,各个重心又保存了所有属于它的点的信息,可以证明,一个点至多属于O(logn)个重心,所有重心拥有的点总和为O(nlogn)。

本质上来说,树的点分治是通过找重心来对树分治,然后建立了一种层次关系(想象一下,找出一棵树的重心,然后在3维空间向上提升,幷让重心向剩下的各块的重心连边,然后再将各块分层,这样就形成了这种层次关系,表现为树结构就是所谓的重心树)。

 /**************************************************************
Problem: 1468
User: idy002
Language: C++
Result: Accepted
Time:6536 ms
Memory:54384 kb
****************************************************************/ #include <cstdio>
#include <vector>
#include <map>
#define fprintf(...)
#define N 40010
#define S 2000000
using namespace std; struct Stat {
int c, d, s;
Stat( int c, int d, int s ):c(c),d(d),s(s){}
};
struct Splay {
static int son[S][], pre[S], key[S], siz[S], ntot;
int root;
void init() { root=; }
inline void update( int nd ) {
siz[nd] = siz[son[nd][]]+siz[son[nd][]]+;
}
void rotate( int nd, int d ) {
int p=pre[nd];
int s=son[nd][!d];
int ss=son[s][d]; son[nd][!d] = ss;
son[s][d] = nd;
if( p ) son[p][ nd==son[p][] ] = s;
else root = s; pre[nd] = s;
pre[s] = p;
if( ss ) pre[ss] = nd; update( nd );
update( s );
}
void splay( int nd, int top= ) {
while( pre[nd]!=top ) {
int p = pre[nd];
int nl = nd==son[p][];
if( pre[p]==top ) {
rotate( p, nl );
} else {
int pp = pre[p];
int pl = p==son[pp][];
if( nl==pl ) {
rotate( pp, pl );
rotate( p, nl );
} else {
rotate( p, nl );
rotate( pp, pl );
}
}
}
}
int newnode( int p, int k ) {
int nd = ++ntot;
son[nd][] = son[nd][] = ;
pre[nd] = p;
key[nd] = k;
siz[nd] = ;
return nd;
}
void insert( int k ) {
if( !root ) {
root = newnode( , k );
return;
}
int nd = root;
while( son[nd][ k>key[nd] ] ) nd=son[nd][ k>key[nd] ];
son[nd][ k>key[nd] ] = newnode( nd, k );
splay( son[nd][ k>key[nd] ] );
}
int query( int k ) {
int nd=root;
int lnd;
int rt = ;
while(nd) {
lnd = nd;
if( key[nd]>k ) {
nd = son[nd][];
} else {
rt += siz[son[nd][]]+;
nd = son[nd][];
}
}
splay( lnd );
return rt;
}
};
int Splay::son[S][], Splay::pre[S], Splay::key[S], Splay::siz[S], Splay::ntot; int n, qdis;
vector<int> g[N], ww[N];
vector<Stat> st[N];
map<int,Splay > spy[N];
int vis[N], anc[N], siz[N], bac[N], dis[N];
int qu[N], bg, ed; void build( int rt ) {
/* find the core of the block containing rt */
qu[bg=ed=] = rt;
anc[rt] = rt;
siz[rt] = bac[rt] = ;
while( ed>=bg ) {
int u=qu[bg++];
for( int t=; t<g[u].size(); t++ ) {
int v=g[u][t];
if( vis[v] || v==anc[u] ) continue;
qu[++ed] = v;
anc[v] = u;
siz[v] = bac[v] = ;
}
}
for( int i=ed; i>=; i-- ) {
int u=qu[i];
int p=anc[u];
siz[u]++;
siz[p] += siz[u];
if( bac[p]<siz[u] ) bac[p]=siz[u];
}
for( int i=ed; i>=; i-- ) {
int u=qu[i];
if( bac[u]<siz[rt]-siz[u] ) bac[u]=siz[rt]-siz[u];
}
for( int i=ed; i>=; i-- ) {
int u=qu[i];
if( bac[u]<bac[rt] ) rt=u;
}
/* statistics the info of the block */
spy[rt][].init();
spy[rt][].insert( );
st[rt].push_back( Stat(rt,,) );
vis[rt] = true;
fprintf( stderr, "%d as core\n", rt );
for( int tm=; tm<g[rt].size(); tm++ ) {
int r=g[rt][tm], w=ww[rt][tm];
if( vis[r] ) continue;
qu[bg=ed=] = r;
anc[r] = rt;
dis[r] = w;
while( ed>=bg ) {
int u=qu[bg++];
for( int t=; t<g[u].size(); t++ ) {
int v=g[u][t], w=ww[u][t];
if( vis[v] || v==anc[u] ) continue;
qu[++ed] = v;
anc[v] = u;
dis[v] = dis[u]+w;
}
}
spy[rt][r].init();
for( int i=ed; i>=; i-- ) {
int u=qu[i];
spy[rt][].insert( dis[u] );
spy[rt][r].insert( dis[u] );
st[u].push_back( Stat(rt,dis[u],r) );
}
build( r );
}
} int main() {
scanf( "%d", &n );
for( int i=,u,v,w; i<n; i++ ) {
scanf( "%d%d%d", &u, &v, &w );
g[u].push_back( v );
g[v].push_back( u );
ww[u].push_back( w );
ww[v].push_back( w );
}
scanf( "%d", &qdis );
build();
for( int u=; u<=n; u++ ) {
fprintf( stderr, "Stat of %d:\n", u );
for( int t=; t<st[u].size(); t++ ) {
fprintf( stderr, "core=%d dis=%d subcore:%d\n", st[u][t].c, st[u][t].d, st[u][t].s );
}
fprintf( stderr, "\n" );
} int ans = ;
for( int u=; u<=n; u++ ) {
int tans=;
for( int t=; t<st[u].size(); t++ ) {
Stat &s = st[u][t];
tans += spy[s.c][].query( qdis-s.d )- (s.s?spy[s.c][s.s].query( qdis-s.d ):);
}
fprintf( stderr, "%d added %d\n", u, tans- );
ans += tans-;
}
printf( "%d\n", ans/ );
}

bzoj 1468的更多相关文章

  1. BZOJ 1468: Tree

    Description 真·树,问距离不大于 \(k\) 的点对个数. Sol 点分治. 同上. Code /********************************************* ...

  2. bzoj 1468 Tree(点分治模板)

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1527  Solved: 818[Submit][Status][Discuss] ...

  3. BZOJ 1468 树分治

    求出子树的重心后求出它每个子节点的距离,排序后就可以统计距离小于等于K的点对的个数了,但是会在同一子树内重复,然后在每个子树里面减去小于等于K的点对个数就可以了. #include <iostr ...

  4. 【BZOJ 1468】Tree 点分治

    点分治$O(nlogn)$ 坚持到月考结束后新校就剩下我一个OIer,其他人早已停课了,老师估计懒得为我一个人开机房门,让我跟班主任说了一声,今晚就回到了老校,开始了自己都没有想到会来的这么早的停课生 ...

  5. BZOJ 1468 & 点分治

    题意: 带权树,求距离小于k的点对数目. SOL: 参考http://blog.csdn.net/jiangshibiao/article/details/25738041解决了题意问题... 代码是 ...

  6. [bzoj 1468][poj 1741]Tree [点分治]

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  7. BZOJ.1468.Tree(点分治)

    BZOJ1468 POJ1741 题意: 计算树上距离<=K的点对数 我们知道树上一条路径要么经过根节点,要么在同一棵子树中. 于是对一个点x我们可以这样统计: 计算出所有点到它的距离dep[] ...

  8. 【刷题】BZOJ 1468 Tree

    Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是 ...

  9. bzoj 1468 Tree 点分

    Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1972  Solved: 1101[Submit][Status][Discuss] Desc ...

随机推荐

  1. Markdown tutorial [repost]

    1. italic We'll start by learning two basic elements in text formatting: italics and bold. In these ...

  2. 【Windows使用笔记】神舟笔记本的control center

    首先,神船大法好. 然后,因为我的船风扇声音有点大啊,在实验室感觉就很吵,但是它的背板温度又不是很高,所以想设置下风扇的启动. 所以需要用到神船自带的control center软件. 长这样. 应该 ...

  3. 74.VS2013和opencv3.1.0安装教程

    一.先下载文件 1.VS2013 VS2013有很多版本,专业版,旗舰版,中文英文之类的,所对应的密钥也不一样.我选择的是简体中文专业版.下载链接如下. http://www.musnow.com/t ...

  4. Battery Charging Specification 1.2 中文详解 来源:www.chengxuyuans.com

    1. Introduction 1.1 Scope 规范定义了设备通过USB端口充电的检测.控制和报告机制,这些机制是USB2.0规范的扩展,用于专用 充电器(DCP).主机(SDP).hub(SDP ...

  5. 记点事! oracle 调用外部命令

    oracle执行系统命令   测试成功环境:windows XP+oracle 10g.window 2008 R2 + 11g   代码如下: www.2cto.com   Sql代码   crea ...

  6. Linux软件管理器(如何使用软件管理器来管理软件)2---安装及管理Linux应用程序

    安装及管理Linux应用程序 Linux应用程序的组成1.普通的可执行程序文件,一般保存在/usr/bin目录中,普通用户即可执行.2.服务器程序.管理程序文件,一般保存在/usr/sbin目录中,需 ...

  7. JavaWeb知识回顾-servlet生命周期。

    Servlet生命周期 生命周期,很容易理解,拿人来说,就是你从出生到离开的这一过程.无论是什么技术,只要谈到生命周期都可以这样理解. Servlet的生命周期就是从它被创建到毁灭的过程,整个过程可以 ...

  8. WordPress插件:WP No Category Base 去除分类Category目录

    不少折腾WordPress的朋友都希望去掉分类链接中的 /category/ 目录标志,网上很多这方面的教程,据倡萌所知,除了使用 WP No Category Base 插件(或类似插件),其他的方 ...

  9. 用户代码未处理EntityCommandExecutionmException报错解决方案

    原因可能是(1)没有编译好,清理解决方案,重新生成解决方案.          (2)可能是WebSiteConfiguration.DbProviderName;中为DbProviderName属性 ...

  10. 检测浏览器对HTML5新input类型的支持

    HTML5新增加了很多input元素类型,比如color,date,datetime,datetime-local,email,month,number,range,search,tel,time,u ...