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的时候被选入,必 ...
随机推荐
- linux命令(5):rm 命令
linux中删除文件和目录的命令: rm命令.rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除.对于链接文件,只是删除了链接,原有 ...
- 让div固定在顶部不随滚动条滚动
让div固定在顶部不随滚动条滚动 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...
- 《Breakfast At Tiffanys》
"生活中似乎有些男性想象着能拯救和引导一个年轻美丽纯洁善良却迷茫的女子,有些女性也想象着能用自己的善良与包容来安慰一个才华横溢却饱经苦闷与贫穷的男子,老实说,这很有成就感.虽然我的语气有些讽 ...
- VLC嵌入网页,终于要成功了!
<OBJECT classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" width="640" heig ...
- Centos实现回收站机制
作为一个运维人员,在服务器上删除文件时为了方便经常会直接使用rm *.txt这类通配符,甚至为了省事加-rf参数,如果是确定的话还好,要是在删除的时候一个不留神,那事可就大了. 俗话说常在河边站哪有不 ...
- JavaWeb 学习007-4个页面,5条sql语句(添加、查看、修改、删除)2016-12-2
需要复习的知识: 关联查询 =================================================================================班级模块学 ...
- laravel中日志为daily时如何设置最大保存天数
在laravel中,日志设置为daily时,默认保存七天的日志,超过则清除七天前的日志.可修改默认的设置,假如要保存30天的日志,则配置如下: 在配置文件config/app.php中添加如下代码: ...
- MongoDB的TruncationException异常解决方法
近期由于DB4O的一些无解的BUG,导致现行的项目查询效率底下,于是愤而迁移到了MongoDB. MongoDB虽然比DB4O的用户要多一些,但是文档依然极度匮乏,遇到问题不是那么容易就能搜到解决办法 ...
- NC nc5.x报表设置合计行是否显示
首先要先继承UI类 /** * 设置合计行是否显示 */ public TotalsReportUI() { super(); getReportBase().getBodyPanel().setTo ...
- [Notes] AWS Automation using script and AWS CLI
(c) 2014 Amazon Web Services, Inc. and its afflialtes, All rights reserved. The content in this file ...