这道题目太神啦!

我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去。那么这样一来看上去似乎就是一次操作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启发式合并)的更多相关文章

  1. 【BZOJ-2888】资源运输 LCT + 启发式合并

    2888: 资源运输 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 63  Solved: 33[Submit][Status][Discuss] D ...

  2. BZOJ 2888 资源运输(启发式合并LCT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2888 [题目大意] 不断加边,问每个连通块的重心到其它点的距离和的和 [题解] 启发式 ...

  3. [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并

    [BZOJ4530][Bjoi2014]大融合 试题描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是 ...

  4. BZOJ.3510.首都(LCT 启发式合并 树的重心)

    题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...

  5. BZOJ2888 : 资源运输

    显然资源集合处就是树的重心,这题需要动态维护树的重心. 每个连通块以重心为根,用link-cut tree维护每个点的子树大小以及子树内所有点到它的距离和. 合并两个连通块时,考虑启发式合并,暴力往大 ...

  6. 4.17 省选模拟赛 远行 LCT 启发式合并 倍增

    容易写出nQ的暴力 由于数据是期望的时间 所以直接dfs可以跑的很快 可以拿到70分. 当然 可以进一步优化暴力 使用换根dp 然后可以将暴力优化到n^2. const int MAXN=300010 ...

  7. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  8. 【bzoj3510】首都 LCT维护子树信息(+启发式合并)

    题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...

  9. CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]

    题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边. 这题还是要考察Kruskal的贪心过程. 先跑一棵MST出来.然后考虑每条边. 如果他是非树边,要让他Kruskal的时候被选入,必 ...

随机推荐

  1. centos7 安装lamp

    1升级gcc4.8以上  yum update gcc2升级openssl     yum update openssl 3安装apache a 安装apr   ./configure --prefi ...

  2. JSTL标准标签库 (使用foreach打印集合)

    <%@page import="java.util.*"%><%@ page language= "java" contentType=&qu ...

  3. JS之BOM、客户端检测和DOM

    这是第八章到第十二章的内容,粗略浏览过一遍. 一.BOM 浏览器对象模型.包括了window.location.navigator.screen和history对象. window:核心对象 1.JS ...

  4. SVM学习笔记(一):libsvm参数说明(转)

    LIBSVM 数据格式需要---------------------- 决策属性 条件属性a 条件属性b ... 2 1:7 2:5 ... 1 1:4 2:2 ... 数据格式转换--------- ...

  5. jQuery的input 失去焦点之后,不能再获取到焦点

    今天写了一个字段唯一性校验功能,验证设备仪器编号唯一,当输入编号之后 ,点击其他,失去焦点后,后台验证唯一,有过此编号,就给出提示,重新填写. 当使用ie时候,获取焦点正常 ,但是使用火狐就获取不到焦 ...

  6. jquery 清空 iframe 的内容,,iframe自适应高度

    $(iframe).contents().find("body").html(""); iframe自适应高度 $("#AllDescription& ...

  7. CoreOS Hyper-V 安装

    CoreOS Hyper-V 安装, Install to disck 准备 安装镜像 https://coreos.com/releases/ 选择版本, 点 Browse Images, 下载以下 ...

  8. Ubuntu 15.10 x64 安装 Android SDK

    操作系统:Ubuntu 15.10 x64 目标:安装 Android SDK 本文最后更新时间:2015-11-3 安装32位库文件 2013年9月的iPhone 5s是第一款64位手机,而Andr ...

  9. 安装 CentOS 后的系统配置及软件安装备忘

    安装 CentOS 后的系统配置及软件安装备忘 // */ // ]]>   安装 CentOS 后的系统配置及软件安装备忘 Table of Contents 1 Linux 自举过程 1.1 ...

  10. JavaScript拼接字符串传递多个参数

    var ftOpreat = function (value,rows){ var v = rows.Version; var preview = "<a href=\"#\ ...