[BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并
[BZOJ4530][Bjoi2014]大融合
试题描述

输入
输出
对每个查询操作,输出被查询的边的负载。
输入示例
A
A
A
A
A
Q
输出示例
题解
LCT + 启发式合并
我不敢直接用LCT直接维护有根树的子树size值,所以每次合并用启发式合并暴力将较小的连通块dfs重构(其实就是换根),再插到另一个连通块中。
当树Tree1的树根要作为另一棵树Tree2中节点u的儿子时,需要将Tree2中节点u到根节点的路径上每个节点的权值加上Tree1的大小,这是一个链上的问题,可以用LCT解决。(代码后附有更强的样例)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define LL long long
int n, q, m, head[maxn], nxt[maxm], to[maxm];
void AddEdge(int a, int b) {
to[++m] = b; nxt[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; nxt[m] = head[a]; head[a] = m;
return ;
} int pa[maxn], siz[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } int fa[maxn], ch[maxn][2], val[maxn], addv[maxn];
bool isroot(int u) { return ch[fa[u]][0] != u && ch[fa[u]][1] != u; }
void pushdown(int u) {
int l = ch[u][0], r = ch[u][1];
if(addv[u]) {
addv[l] += addv[u]; addv[r] += addv[u];
val[l] += addv[u]; val[r] += addv[u];
addv[u] = 0;
}
return ;
}
void maintain(int u) {
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(ch[y][1] == u) swap(l, r);
if(!isroot(y)) ch[z][ch[z][1]==y] = u;
fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
ch[y][l] = ch[u][r]; ch[u][r] = y;
maintain(y); maintain(u);
return ;
}
int S[maxn], top;
void splay(int u) {
S[++top] = u;
for(int t = u; !isroot(t); t = fa[t]) S[++top] = fa[t];
while(top) pushdown(S[top--]);
while(!isroot(u)) {
int y = fa[u], z = fa[y];
if(!isroot(y)) {
if((ch[y][0] == u) ^ (ch[z][0] == u)) rotate(u);
else rotate(y);
}
rotate(u);
}
return ;
}
void access(int u) {
for(int t = 0; u; u = fa[u]) {
splay(u); ch[u][1] = t; maintain(u); t = u;
}
return ;
}
void add(int u, int v) {
access(u); splay(u); addv[u] += v; val[u] += v;
return ;
}
int query(int u) {
access(u); splay(u);
return val[u];
}
void rebuild(int u) {
ch[u][0] = ch[u][1] = 0;
val[u] = 1;
for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u]) {
fa[to[e]] = u;
rebuild(to[e]);
val[u] += val[to[e]];
}
return ;
} int main() {
n = read(); q = read();
for(int i = 1; i <= n; i++) pa[i] = i, val[i] = siz[i] = 1;
while(q--) {
char tc = Getchar();
while(!isalpha(tc)) tc = Getchar();
int u = read(), v = read();
if(tc == 'A') {
int a = findset(u), b = findset(v);
if(siz[a] > siz[b]) swap(a, b), swap(u, v);
pa[a] = b; siz[b] += siz[a];
fa[u] = v; AddEdge(u, v);
rebuild(u);
// printf("siz[%d] val[%d]: %d %d\n", b, u, siz[b], val[u]);
add(v, siz[a]);
}
if(tc == 'Q') {
LL x = (LL)min(query(u), query(v));
// printf("%d %d\n", query(u), query(v));
printf("%lld\n", x * (siz[findset(u)] - x));
}
} return 0;
}
/*
in:
8 14
A 2 3
Q 2 3
A 3 4
Q 2 3
A 3 8
Q 3 8
A 8 7
Q 3 4
A 6 5
Q 5 6
Q 3 8
A 1 6
A 1 8
Q 1 8
out:
1
2
3
4
1
6
15
*/
[BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并的更多相关文章
- BZOJ4530:[BJOI2014]大融合(LCT)
Description 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它 ...
- BZOJ4530[Bjoi2014]大融合——LCT维护子树信息
题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它的简单路径的数 ...
- 【BZOJ-4530】大融合 线段树合并
4530: [Bjoi2014]大融合 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 280 Solved: 167[Submit][Status] ...
- [bzoj4530][Bjoi2014]大融合_LCT
大融合 bzoj-4530 Bjoi-2014 题目大意:n个点,m个操作,支持:两点连边:查询两点负载:负载.边(x,y)的负载就是将(x,y)这条边断掉后能和x联通的点的数量乘以能和y联通的点的数 ...
- BZOJ4530: [Bjoi2014]大融合
Description 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它 ...
- BZOJ4530 BJOI2014大融合(线段树合并+并查集+dfs序)
易知所求的是两棵子树大小的乘积.先建出最后所得到的树,求出dfs序和子树大小.之后考虑如何在动态加边过程中维护子树大小.这个可以用树剖比较简单的实现,但还有一种更快更优美的做法就是线段树合并.对每个点 ...
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...
- 2019.01.14 bzoj4530: [Bjoi2014]大融合(线段树合并)
传送门 线段树合并菜题. 题意简述:nnn个点,支持连边以及查询一个点所在连通块中经过这个点的路径条数,保证这张图时刻为森林. 思路: 先建出所有操作完之后的树统计出dfsdfsdfs序 注意有可能是 ...
- [BZOJ4530][Bjoi2014]大融合(LCT)
传送门 大佬们似乎都是用树剖+并查集优雅地A了此题 然后我太弱了,只能打打LCT的板子 虽然的确可以挺无脑的A掉…… 不过至少这题教了我该怎么维护LCT上虚子树的信息,具体看这里 首先,答案很明显是断 ...
随机推荐
- Bootstrap系列 -- 22. 按钮
Bootstrap框架首先通过基础类名“.btn”定义了一个基础的按钮风格,然后通过“.btn-default”定义了一个默认的按钮风格.默认按钮的风格就是在基础按钮的风格的基础上修改了按钮的背景颜色 ...
- 项目笔记---Socket Error Code翻译
前言 在项目中为了方便调试及客户反馈,需要Socket错误数字的中文解释,MSDN上只有英文版,同时也想自己学习而且方便将来更新ErrorCode的实际发生的情景,顾有此博文. MSDN:https: ...
- Javascript的io操作
一.功能实现核心:FileSystemObject 对象 要在javascript中实现文件操作功能,主要就是依靠FileSystemobject对象. 二.FileSystemObject编程 使用 ...
- 在Myeclipse buildpath 加server lib (server runtime)/项目导入时报错:The import javax.servlet.http.HttpServletRequest cannot be resolved
来源于:http://blog.csdn.net/dingqinghu/article/details/8805922 http://yl-fighting.iteye.com/blog/140946 ...
- [转]Java中继承、多态、重载和重写介绍
什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上 ...
- VS中两个常用辅助工具
一. 首当推荐的是DPack 下载地址:http://www.usysware.com/dpack/ 快捷键:以下都是个人常用的热键.其他还有,我都用得比较少了,3个已经完全够了 Alt+U 查找 ...
- Tomcat_修改代码后tomcat是否需要重启
在修改一个类时,如果没有修改到已经贮存于虚拟机的实例,在你重新编译后,发布至classes,都不需要重启. 怎样才叫已经贮存于虚拟机的实例呢: 1.成员变量 2.类名称 3.方法名 ………… 如果 ...
- 【codevs 1200】【NOIP 2012】同余方程 拓展欧几里德求乘法逆元模板题
模板,,, #include<cstdio> using namespace std; void exgcd(long long a,long long b,long long & ...
- 读JS高级(兼容&&BOM&&私有变量&&面向对象)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- nodeJs抓取网页
var fs = require('fs'); var jquery = require('jquery'); var url = require('url'); var data = { 0 : ' ...