4530: [Bjoi2014]大融合

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 280  Solved: 167
[Submit][Status][Discuss]

Description

小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。

Input

第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
1≤N,Q≤100000

Output

对每个查询操作,输出被查询的边的负载。

Sample Input

8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8

Sample Output

6

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】大融合 线段树合并的更多相关文章

  1. BZOJ.3545.[ONTAK2010]Peaks(线段树合并)

    题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. \(Solut ...

  2. bzoj 4631: 踩气球 线段树合并

    4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 265  Solved: 136[Submit][Status][Discuss] ...

  3. BZOJ:5457: 城市(线段树合并)(尚待优化)

    5457: 城市 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 18  Solved: 12[Submit][Status][Discuss] Des ...

  4. 洛谷 4219/BZOJ 4530 大融合

    4530: [Bjoi2014]大融合 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 990  Solved: 604[Submit][Status] ...

  5. bzoj 4756 Promotion Counting —— 线段树合并

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756 合并子树的权值线段树: merge 返回 int 或者是 void 都可以. 代码如下 ...

  6. [BZOI2014]大融合——————线段树进阶

    竟然改了不到一小时就改出来了, 可喜可贺 Description Solution 一开始想的是边两侧简单路径之和的乘积,之后发现这是个树形结构,简单路径数就是节点数. 之后的难点就变成了如何求线段树 ...

  7. bzoj 4530 大融合 —— LCT维护子树信息

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530 用LCT维护子树 size,就是实边和虚边分开维护: 看博客:https://blog ...

  8. BZOJ4530 BJOI2014大融合(线段树合并+并查集+dfs序)

    易知所求的是两棵子树大小的乘积.先建出最后所得到的树,求出dfs序和子树大小.之后考虑如何在动态加边过程中维护子树大小.这个可以用树剖比较简单的实现,但还有一种更快更优美的做法就是线段树合并.对每个点 ...

  9. 2019.01.14 bzoj4530: [Bjoi2014]大融合(线段树合并)

    传送门 线段树合并菜题. 题意简述:nnn个点,支持连边以及查询一个点所在连通块中经过这个点的路径条数,保证这张图时刻为森林. 思路: 先建出所有操作完之后的树统计出dfsdfsdfs序 注意有可能是 ...

随机推荐

  1. Linux通过ssh登录其他服务器,不用输入密码

    有A(192.168.10.163)和B(192.168.10.164)两台服务器,为了使A服务器通过SSH连接B服务器时,免密登录,做以下操作. 1. 登录A(192.168.10.163)服务器( ...

  2. My latest news

    2018.04.12  0:01 本站点停止更新,启用0x7c00.vip站点. 2018.03.23 复试报道(心态不太平稳).每一行的深入都是需要知识的积累和时间的沉淀,就像学法律.计算机等等.愿 ...

  3. Spring Mvc 一个接口多个继承; (八)

    在 spring 注解实现里,一个接口一般是不能多继承的! 除非在 bean 配置文件里有 针对这个 实现类的配置: <beans:bean id="icService" c ...

  4. HTML5 移动开发(移动设备检测及对HTML5的支持)

    1.如何选择要使用的特性以及所面向的浏览器 2.哪些浏览器支持HTML5 3.如何检测是否支持HTML5 4.如何开发贷容错性的Web应用程序 5.CSS3媒体查询如何增强检测脚本   使用HTML5 ...

  5. hibernate介绍及环境搭建

    1.前言 hibernate与mybatis的位置一样,都是属于DAO层的框架,代替我们原来的JDBC操作数据库,属于ORM(object relationg mapping. 对象关系映射)框架.O ...

  6. Robotium_断言方法assert、is、search

    下面的这些方法都主要用来判断测试结果是否与预期结果相符,一般把is和search方法放在assert里面判断.assert最常用的还是assertThat方法,是Junit的判断,这里就不多说了.断言 ...

  7. php ++测试

    2014年4月27日 12:17:47 结论暂时没有组织语言去表述,但是看看测试结果大家都会明白的 $x = 1; $y = empty($x) ? 3 : $x++; var_dump($x,$y) ...

  8. 用原生js实现ajax

    // 通过createXHR()函数创建一个XHR对象 function createXHR() { if(window.XMLHttpRequest) { // IE7.Firefox.Opera. ...

  9. Java流程控制练习--万年历

    Java流程控制练习--万年历 标签: Java入坑之旅 0x01. 打印倒三角和正三角 public static void main(String[] args) { // TODO Auto-g ...

  10. activiti helloworld 续

    todo... 8.开发流程部署功能 9.开发简单任务待办功能 10.开发简单任务办理功能 11.开发页面activiti流程跟踪图形展现功能 12.集成网页流程设计器