BZOJ2888 资源运输(LCT启发式合并)
这道题目太神啦!
我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去。那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器——启发式合并,那么我们就可以在均摊O(log2n)的时间内合并一颗树,这题就可以完美的AC啦!
什么,你问怎么维护重心?我们可以记录一个值sb表示子树的大小。怎么维护sb呢?我们可以采用打标记的方法,把新加入的节点到根的路径上的点的sb值都+1
对于维护答案,我们维护一个sm变量,来保存子树内所有节点到这个节点的距离之和,在更新的时候采用维护一个等差数列的方法,记录首项和公差,然后在pushdown的时候如果走给Splay的左儿子,那么还要加上这个点的右儿子到首项上(因为右儿子实际上是左儿子的后代(LCT意义下))。
#include <cstdio>
#include <algorithm>
#include <assert.h>
using namespace std;
#define MAXN 40005
#define lc(x) (t[x].s[0])
#define rc(x) (t[x].s[1])
int n, m, adj[MAXN], c, ans;
inline void GET(int &n) {
char c; n = 0;
do c = getchar(); while(c > '9' || c < '0');
while(c >= '0' && c <= '9') {n=n*10+c-'0';c=getchar();}
}
struct Node { int v, nxt; } e[MAXN << 1];
inline void add(int u, int v) {
++ c; e[c].v = v; e[c].nxt = adj[u]; adj[u] = c;
}
struct Link_Cut_Cactus {
int fa[MAXN], sta[MAXN];
struct Spaly { int f, sz, a, d, sm, s[2], sb, db; } t[MAXN];
/**依次表示爸爸,spaly字数大小,首项,公差,子树到此节点的距离,儿子,子树大小**/
inline void init() { for(int i = 1; i <= n; ++ i) t[i].sz = t[i].sb = 1; }
inline void pushup(int x) { t[x].sz = t[lc(x)].sz + t[rc(x)].sz + 1; }
inline void add1(int x, int tag) {
if(x) { t[x].sb += tag; t[x].db += tag; }
}
inline void add2(int x, int a, int d) {
if(x) { t[x].sm += a + t[rc(x)].sz * d; t[x].a += a; t[x].d += d; }
}
inline void pushdown(int x) {
if(t[x].db) { add1(lc(x), t[x].db); add1(rc(x), t[x].db); t[x].db = 0; }
if(t[x].d) { add2(lc(x), t[x].a + (t[rc(x)].sz+1)*t[x].d, t[x].d); add2(rc(x), t[x].a, t[x].d); t[x].d = 0; }
}
inline void rot(int x) {
int y = t[x].f, z = t[y].f;
bool f = rc(y) == x;
fa[x] = fa[y]; t[x].f = z;
t[y].s[f] = t[x].s[f^1];
t[x].s[f^1] = y; t[y].f = x;
if(t[y].s[f]) t[t[y].s[f]].f = y;
if(z) t[z].s[ rc(z) == y ] = x;
pushup(y);
}
inline void Splay(int x) {
int tp = 0;
for(int p = x; p; p = t[p].f) sta[++ tp] = p;
while(tp) pushdown(sta[tp --]);
for(int y, z; (y = t[x].f); rot(x)) {
z = t[y].f; if(!z) continue;
if((rc(z) == y) == (rc(y) == x)) rot(y);
else rot(x);
}
pushup(x);
}
inline void expose(int x, int y = 0) {
Splay(x);
if(t[x].s[1]) {
t[t[x].s[1]].f = 0;
fa[t[x].s[1]] = x;
}
t[x].s[1] = y;
if(y) t[y].f = x;
pushup(x);
}
inline void access(int x, int y = 0) {
while(x) { expose(x, y); y = x; x = fa[x]; }
}
inline int root(int x) {
access(x); Splay(x); while(lc(x)) x = lc(x); return Splay(x), x;
}
inline void addleaf(int x, int to) {
fa[x] = to; t[x].sz = 1; t[x].a = lc(x) = rc(x) = 0;
t[x].d = t[x].db = t[x].f = t[x].sb = t[x].sm = 0;
to = root(to); access(x); Splay(to); add1(to, 1); add2(to, 0, 1);
for(x = rc(to); lc(x); x = lc(x)); Splay(x);
int vx = t[to].sb, vy = t[x].sb;
if(vy * 2 > vx) {
t[x].sb = vx; t[to].sb -= vy;
t[to].sm -= t[x].sm + vy;
t[x].sm += t[to].sm + vx - vy;
access(x); Splay(to);
swap(lc(to), rc(to));
}
}
void dfs(int u, int fa) {
addleaf(u, fa);
for(int i = adj[u]; i; i = e[i].nxt)
if(e[i].v != fa) dfs(e[i].v, u);
}
void Link(int u, int to) {
int x = root(u), y = root(to);
ans -= t[x].sm + t[y].sm;
if(t[x].sb < t[y].sb) swap(u, to);
dfs(to, u); add(u, to); add(to, u);
ans += t[root(u)].sm;
}
} lct;
int main() {
char op[5]; int u, v;
scanf("%d%d", &n, &m);
lct.init();
for(int i = 1; i <= m; ++ i) {
scanf("%s", op);
if(op[0] == 'A') {
GET(u); GET(v); lct.Link(u, v);
}
else printf("%d\n", ans);
}
return 0;
}
BZOJ2888 资源运输(LCT启发式合并)的更多相关文章
- 【BZOJ-2888】资源运输 LCT + 启发式合并
2888: 资源运输 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 63 Solved: 33[Submit][Status][Discuss] D ...
- BZOJ 2888 资源运输(启发式合并LCT)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2888 [题目大意] 不断加边,问每个连通块的重心到其它点的距离和的和 [题解] 启发式 ...
- [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并
[BZOJ4530][Bjoi2014]大融合 试题描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是 ...
- BZOJ.3510.首都(LCT 启发式合并 树的重心)
题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...
- BZOJ2888 : 资源运输
显然资源集合处就是树的重心,这题需要动态维护树的重心. 每个连通块以重心为根,用link-cut tree维护每个点的子树大小以及子树内所有点到它的距离和. 合并两个连通块时,考虑启发式合并,暴力往大 ...
- 4.17 省选模拟赛 远行 LCT 启发式合并 倍增
容易写出nQ的暴力 由于数据是期望的时间 所以直接dfs可以跑的很快 可以拿到70分. 当然 可以进一步优化暴力 使用换根dp 然后可以将暴力优化到n^2. const int MAXN=300010 ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]
题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边. 这题还是要考察Kruskal的贪心过程. 先跑一棵MST出来.然后考虑每条边. 如果他是非树边,要让他Kruskal的时候被选入,必 ...
随机推荐
- jquery指index
$(selector).index(element) 获得元素相对于选择器的 index 位置.<ul> <li><a href="#nogo" ...
- funny_python 00 The Zen of Python
# 打算每天多动的时候尽量搜索一些和coding相关的funny stuff Day 00 - PEP 20 The Zen of Python 在shell里面输入python -m this 回车 ...
- hdu4044 GeoDefense
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4044 题意:一个树上的塔防游戏.给你n个结点的树,你要在树结点上建塔防御,在第 i 个结点上有 ki ...
- IT行业果真跳槽快吗?
近年来IT行业越来越火爆,许多人也开始炒,月入万元不是梦,随随便便拿高薪之类的文章层出不穷,许多的青少年甚至中年人开始关注这块,许多人选择去学习it行业,也朝着月入万元的目标前进,然而,曾几何时,月入 ...
- mybatis组合模糊+分页查询
//组合模糊查询就是这么简单 <select id="findAllJiemu" parameterType="java.util.Map" result ...
- iOS错误总结(三)
1.如果tableView设置为分组的样式(默认是有cell之间的分割线,可以设置颜色),默认有组以及组尾的高度 需要手动在组头组尾的代理方法中进行组高的设置(如果想设置为0,最好写0.01) 2.组 ...
- Android之listview && adapter
今天我们讲的也是非常重要的一个控件listview-最常用也是最难的 一个ListView通常有两个职责. (1)将数据填充到布局. (2)处理用户的选择点击等操作. 第一点很好理解,ListView ...
- angular+ionic返回上一页并刷新
假定当前页面为editCata页面,要返回的是cataDetail页面.目前我找到两种方法实现返回上一页并刷新,如果以后有其它方法,再继续添加. 1.在editCataCtrl.js中注入$ionic ...
- CSS布局设计
CSS布局设计: (1)固定布局:各个部分采用固定宽度的页面布局. (2)流式布局:通过定义模块和模块间距的百分比的方式来实现.缺点是会自动缩放,影响图片的美观. (3)响应式布局:页面可以用户的设备 ...
- 项目里面Swift和OC 交叉使用
在OC的项目中使用Swift 语言开发 创建swift文件,同时创建桥接文件.(桥接文件里面不用导入头文件) 在swift文件中完成代码的编写. 在某OC类的.m文件中,使用swift文件.方法;#i ...