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

用这种方式实现的话,还可以支持修改与多次查询,每次操作都是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. HDU 1045 Fire Net (深搜)

    题目链接 Problem DescriptionSuppose that we have a square city with straight streets. A map of a city is ...

  2. eWebEditor复制粘贴图片时过滤域名

    1.找到form.js 路径:plugins/frame/scripts/form.js 这个方法: 2.替换这个方法 /** * 处理参数 */ Form.prototype.processReqP ...

  3. 用C++写程序的一些感悟

    前言 近期使用C++有了一些心得很感悟,这里整理一下. 心得1 如果只会使用LabVIEW写程序,还想要进一步深入程序设计,一定要学习一门文本语言. 什么是会用LabVIEW 会用是个比较笼统的概念. ...

  4. 苹果笔记本MacBookPro 的新手使用技巧

    Mac 系统的桌面 Mac 的桌面是一个很炫的3D, 背景是一张“星空”图 Dock:  在桌面的下方,有一排图标, 这个叫Dock, 用来快速启动程序, 进入文件夹, 它同时还可以停靠正在运行的程序 ...

  5. Oracle安装出现报错

    报错信息如下: >>> Couldnot execute auto check for display colors using command /usr/bin/xdpyinfo. ...

  6. sed的额外用法(网摘)

    #在我开始动手写一个一个的脚本的时候才会看到更多的用法 1. 在某行的前一行或后一行添加内容(前提是要确定行的内容) # 匹配行前加 sed -i '/allow/ideny' httpd.conf ...

  7. svm和svr区别--摘自其它博客

    学习笔记:SVM柔性边界的补充和SVR(支持向量回归) 作者 小刺猬yyx 关注 2016.08.06 10:31* 字数 1608 阅读 421评论 0喜欢 2 上一个笔记对于SVM不能完美分类的情 ...

  8. 邀请用户进TestFlight 体验 App 的测试版本

    iphone手机用户,在工作中常见到,APP版本现在是Beta阶段(iOS版本),需要邀请一些用户来体验新版本,在版本上线前提出更好的建议及时进行修改,此时用到了testflight,很方便的通过邀请 ...

  9. IEEEXtreme 10.0 - Goldbach's Second Conjecture

    这是 meelo 原创的 IEEEXtreme极限编程大赛题解 Xtreme 10.0 - Goldbach's Second Conjecture 题目来源 第10届IEEE极限编程大赛 https ...

  10. 【58沈剑架构系列】lvs为何不能完全替代DNS轮询

    上一篇文章“一分钟了解负载均衡的一切”引起了不少同学的关注,评论中大家争论的比较多的一个技术点是接入层负载均衡技术,部分同学持这样的观点: 1)nginx前端加入lvs和keepalived可以替代“ ...