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

用这种方式实现的话,还可以支持修改与多次查询,每次操作都是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. Balanced and stabilized quicksort method

    The improved Quicksort method of the present invention utilizes two pointers initialized at opposite ...

  2. MySQL删除数据几种情况以及是否释放磁盘空间【转】

    MySQL删除数据几种情况以及是否释放磁盘空间: 1.drop table table_name 立刻释放磁盘空间 ,不管是 Innodb和MyISAM ; 2.truncate table tabl ...

  3. 008 BlockingQueue理解

    原文https://www.cnblogs.com/WangHaiMing/p/8798709.html 本篇将详细介绍BlockingQueue,以下是涉及的主要内容: BlockingQueue的 ...

  4. /proc/cpuinfo 文件分析(查看CPU信息)

    /proc/cpuinfo文件分析 根据以下内容,我们则可以很方便的知道当前系统关于CPU.CPU的核数.CPU是否启用超线程等信息. <1>查询系统具有多少个逻辑核:cat /proc/ ...

  5. Apache虚拟主机配置(多个域名访问多个目录)(转)

    Apache虚拟主机配置(多个域名访问多个目录) 为了方便管理虚拟主机,我决定使用一种方法,那就是修改httpd-vhosts.conf文件. 第一步首先要使扩展文件httpd-vhosts.conf ...

  6. [ python ] 网络编程(1)

    在本地电脑上有两个python文件 regist.py .login.py 一个注册,一个登录.这两个python一个是写用户信息,一个是读用户信息,要怎么做呢? 通过之前的知识,我们可以通过 reg ...

  7. Activity工作流 -- java运用

    一. 什么是工作流 以请假为例,现在大多数公司的请假流程是这样的 员工打电话(或网聊)向上级提出请假申请——上级口头同意——上级将请假记录下来——月底将请假记录上交公司——公司将请假录入电脑 采用工作 ...

  8. Merge k Sorted Lists——分治与堆排序(需要好好看)

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 1 ...

  9. 转载:C++ typename的起源与用法

    转载:http://feihu.me/blog/2014/the-origin-and-usage-of-typename/#typename 侯捷在Effective C++的中文版译序中提到: C ...

  10. 安装 jupyter notebook 出现 ModuleNotFoundError: No module named 'markupsafe._compat' 错误

    使用 python -m pip install jupyter 安装完成 jupyter notebook 之后,在命令行界面输入 "jupyter notebook "指令打开 ...