bzoj 1468
大概思路:树点分治,重心树中每个重心维护一个总的平衡树,树中保存属于该重心的点到该重心的距离,然后对于去掉该重心后形成的子树分别再保存一份。
用这种方式实现的话,还可以支持修改与多次查询,每次操作都是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的更多相关文章
- BZOJ 1468: Tree
Description 真·树,问距离不大于 \(k\) 的点对个数. Sol 点分治. 同上. Code /********************************************* ...
- bzoj 1468 Tree(点分治模板)
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1527 Solved: 818[Submit][Status][Discuss] ...
- BZOJ 1468 树分治
求出子树的重心后求出它每个子节点的距离,排序后就可以统计距离小于等于K的点对的个数了,但是会在同一子树内重复,然后在每个子树里面减去小于等于K的点对个数就可以了. #include <iostr ...
- 【BZOJ 1468】Tree 点分治
点分治$O(nlogn)$ 坚持到月考结束后新校就剩下我一个OIer,其他人早已停课了,老师估计懒得为我一个人开机房门,让我跟班主任说了一声,今晚就回到了老校,开始了自己都没有想到会来的这么早的停课生 ...
- BZOJ 1468 & 点分治
题意: 带权树,求距离小于k的点对数目. SOL: 参考http://blog.csdn.net/jiangshibiao/article/details/25738041解决了题意问题... 代码是 ...
- [bzoj 1468][poj 1741]Tree [点分治]
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- BZOJ.1468.Tree(点分治)
BZOJ1468 POJ1741 题意: 计算树上距离<=K的点对数 我们知道树上一条路径要么经过根节点,要么在同一棵子树中. 于是对一个点x我们可以这样统计: 计算出所有点到它的距离dep[] ...
- 【刷题】BZOJ 1468 Tree
Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是 ...
- bzoj 1468 Tree 点分
Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1972 Solved: 1101[Submit][Status][Discuss] Desc ...
随机推荐
- Linux下查看进程占用内存的最好方式
今天看到stackoverflow上关于linux下如何查看某个进程占用的内存是多少的回答,觉得非常棒,不过是全英文的,很多人可能看不懂,所以我翻译一下 翻译自http://stackoverflow ...
- LCD常用接口原理【转】
转自:http://blog.csdn.net/wocao1226/article/details/23870149 LCD常用接口原理 点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打 ...
- Arm-kernel 内存收集【转】
转自:http://blog.csdn.net/linyt/article/details/6627664 Linux kernel的内存管理子系统非常复杂,为了深入了解内存管理系统,我打算分多篇文章 ...
- kvm 简单了解
网络: *主机(装有ESX的PC服务器)简称host,虚拟机简称guest *Host的一个或多个网卡组成一个虚拟交换机,虚拟交换机上创建端口组label,端口组指定vlan tag,虚拟机指定网络标 ...
- 145.Binary Tree Postorder Traversal---二叉树后序非递归遍历
题目链接 题目大意:后序遍历二叉树. 法一:普通递归,只是这里需要传入一个list来存储遍历结果.代码如下(耗时1ms): public List<Integer> postorderTr ...
- 「pycaffe指南」使用caffe的NetSpec.py中的Python接口自动生成×.prototxt文件
https://www.jianshu.com/p/1a420445deea 作者:MapReducer 链接:https://www.jianshu.com/p/1a420445deea 來源:简书 ...
- ubuntu中安装软件包问题 ------有一些软件包无法被安装。如果您用的是 unstable 发行版。。。
在ubuntu中安装软件包提示 有一些软件包无法被安装.如果您用的是 unstable 发行版,这也许是因为系统无法达到您要求的状态造成的.该版本中可能会有一些您需要的软件包尚未被创建或是它们已被从新 ...
- linux下rz,sz安装
1.sz rz yum安装 yum install lrzsz
- 解决uc浏览器不支持vw单位的方法
插入下段代码,使用rem来代替vw <script type="text/javascript"> (function (doc, win) { var docEl = ...
- fail2ban安全设置
1.先安装fail2ban服务包(这里我采用的是fail2ban-0.8.14.tar.gz) 2.解压安装包 cd /data/software tar xzf fail2ban-0.8.14.ta ...