【BZOJ-4530】大融合 线段树合并
4530: [Bjoi2014]大融合
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 280 Solved: 167
[Submit][Status][Discuss]
Description

Input
Output
Sample Input
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
Sample Output
HINT
Source
Solution
这题的思路还是很好的,自己思考了一段时间才能想出来。
对于一次询问$<u,v>$,答案显然就是$size[u]*size[v]$,但是需要维护这样的树的形态并且询问。
然后我想了一种线段树合并的方法,但是蛋疼的地方是询问时的$size$很鸡肋,不能直接询问。
因为合并时是合并到一个点上,其余的点的线段树形态并不完整,这个地方其实和并查集很类似,那么再用并查集维护一下每个块的代表元素即可。
这样查询另一个点时也会有问题,那么限定查询区间为dfs序两端即可,然后这个题就很简单了,然后这个问题就转化成了$(size[root]-size[u])*size[u]$。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
} #define MAXN 200010 int N,Q; struct EdgeNode{
int next,to;
}edge[MAXN];
int head[MAXN],cnt=1;
inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);} int fa[MAXN];
inline int F(int x) {if (fa[x]==x) return x; else return fa[x]=F(fa[x]);} struct SgtNode{
int lson,rson,size;
}tree[MAXN*20];
int root[MAXN],sz; inline void Update(int x) {tree[x].size=tree[tree[x].lson].size+tree[tree[x].rson].size;} inline int Merge(int x,int y)
{
if (!x || !y) return x|y;
tree[x].size+=tree[y].size;
tree[x].lson=Merge(tree[x].lson,tree[y].lson);
tree[x].rson=Merge(tree[x].rson,tree[y].rson);
return x;
} inline void Insert(int &x,int l,int r,int pos)
{
x=++sz;
if (l==r) {
tree[x].size=1;
return;
}
int mid=(l+r)>>1;
if (pos<=mid) Insert(tree[x].lson,l,mid,pos);
else Insert(tree[x].rson,mid+1,r,pos);
Update(x);
} inline int Query(int x,int l,int r,int L,int R)
{
if (!x) return 0;
if (L<=l && R>=r) return tree[x].size;
int mid=(l+r)>>1,re=0;
if (L<=mid) re+=Query(tree[x].lson,l,mid,L,R);
if (R>mid) re+=Query(tree[x].rson,mid+1,r,L,R);
return re;
} int pl[MAXN],pre[MAXN],pr[MAXN],dfn,deep[MAXN];
inline void DFS(int now,int last)
{
pl[now]=++dfn; pre[dfn]=now;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
deep[edge[i].to]=deep[now]+1,
DFS(edge[i].to,now);
pr[now]=dfn;
} struct QNode{
int opt,x,y;
}Qr[MAXN]; int main()
{
N=read(),Q=read(); for (int i=1; i<=Q; i++) {
char opt[5]; scanf("%s",opt+1);
int x=read(),y=read();
if (opt[1]=='A') InsertEdge(x,y);
Qr[i]=(QNode){(opt[1]=='A'? 0:1),x,y};
} for (int i=1; i<=N; i++) if (!deep[i]) DFS(i,0); for (int i=1; i<=N; i++) fa[i]=i,Insert(root[i],1,N,pl[i]); for (int i=1; i<=Q; i++) {
if (Qr[i].opt==0) {
int x=F(Qr[i].x),y=F(Qr[i].y);
if (deep[x]>deep[y]) swap(x,y);
root[x]=Merge(root[x],root[y]);
fa[y]=x;
} else {
int x=Qr[i].x,y=Qr[i].y,z;
if (deep[x]<deep[y]) swap(x,y); z=F(x);
int siz=Query(root[z],1,N,pl[x],pr[x]);
printf("%lld\n",1LL*(tree[root[z]].size-siz)*siz);
}
} return 0;
}
【BZOJ-4530】大融合 线段树合并的更多相关文章
- BZOJ.3545.[ONTAK2010]Peaks(线段树合并)
题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. \(Solut ...
- bzoj 4631: 踩气球 线段树合并
4631: 踩气球 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 265 Solved: 136[Submit][Status][Discuss] ...
- BZOJ:5457: 城市(线段树合并)(尚待优化)
5457: 城市 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 18 Solved: 12[Submit][Status][Discuss] Des ...
- 洛谷 4219/BZOJ 4530 大融合
4530: [Bjoi2014]大融合 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 990 Solved: 604[Submit][Status] ...
- bzoj 4756 Promotion Counting —— 线段树合并
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756 合并子树的权值线段树: merge 返回 int 或者是 void 都可以. 代码如下 ...
- [BZOI2014]大融合——————线段树进阶
竟然改了不到一小时就改出来了, 可喜可贺 Description Solution 一开始想的是边两侧简单路径之和的乘积,之后发现这是个树形结构,简单路径数就是节点数. 之后的难点就变成了如何求线段树 ...
- bzoj 4530 大融合 —— LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530 用LCT维护子树 size,就是实边和虚边分开维护: 看博客:https://blog ...
- BZOJ4530 BJOI2014大融合(线段树合并+并查集+dfs序)
易知所求的是两棵子树大小的乘积.先建出最后所得到的树,求出dfs序和子树大小.之后考虑如何在动态加边过程中维护子树大小.这个可以用树剖比较简单的实现,但还有一种更快更优美的做法就是线段树合并.对每个点 ...
- 2019.01.14 bzoj4530: [Bjoi2014]大融合(线段树合并)
传送门 线段树合并菜题. 题意简述:nnn个点,支持连边以及查询一个点所在连通块中经过这个点的路径条数,保证这张图时刻为森林. 思路: 先建出所有操作完之后的树统计出dfsdfsdfs序 注意有可能是 ...
随机推荐
- CSS currentColor研究
刚刚写了篇<CSS变量试玩儿>,我们了解到可以使用原生的CSS来定义使用变量,简化CSS书写.优化代码的组织与维护,但可怕的兼容性问题,又让我们望而却步.一笑了之. 但是有这么一个CSS变 ...
- [整理]ASP.NET 中异常处理
[整理]ASP.NET 中异常处理 1.直接通过重写Controller的OnException来处理异常 public class HomeController : Controller { pub ...
- 【整理】HTML5游戏开发学习笔记(3)- 抛物线运动
1.预备知识(1)Canvas旋转的实现过程 window.onload = function(){ var ctx = document.getElementById('canvas1').getC ...
- 高品质的JavaScript
整理书籍内容(QQ:283125476 发布者:M [重在分享,有建议请联系->QQ号]) 养成良好的编程习惯 ##如何避免团队JS冲突 * 避免实用全局变量[可使用匿名函数进行处理]以避免全局 ...
- CS229 笔记04
CS229 笔记04 Logistic Regression Newton's Method 根据之前的讨论,在Logistic Regression中的一些符号有: \[ \begin{eqnarr ...
- 20155338 2016-2017-2 《Java程序设计》第6周学习总结
20155338 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 输入和输出 • 串流设计概念 要想活用输入/输出API,一定先要了解Java中如何以串流抽象 ...
- Xcode多种Build Configuration配置使用
Build Configuration? Xcode默认会有2个编译模式,一个是Debug,一个是Release.Release下不能调试程序,编译时有做编译优化,会比用Debug打包出来的运行快,另 ...
- os_cpu_a.asm
在OS_CPU_A.ASM中,定义了开.关中断的方法,在uC/OS-II系统中有三种方法可以实现中断开关,而ARM只适用于模式三,即使用一个局部变量,在中断进入之间保存CPU状态,退出时候再恢复状态. ...
- python版本管理工具pyenv和包管理工具pipenv
一.pyenv版本管理工具 pyenv是一个python版本管理工具,可以实现轻松切换多个python版本 它可根据每个用户更改全局python版本,也可以为每个项目指定python版本,还可以管理v ...
- Linux中Samba详细安装【转】
转自:http://www.cnblogs.com/whiteyun/archive/2011/05/27/2059670.html 为了实现Windows主机与Linux服务器之间的资源共享,Lin ...