【BZOJ4530】大融合(Link-Cut Tree)

【BZOJ4530】大融合(Link-Cut Tree)

题面

讨厌权限题!!!

Loj链接

题目描述

小强要在 N个孤立的星球上建立起一套通信系统。这套通信系统就是连接 N个点的一个树。这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。

例如,在上图中,现在一共有五条边。其中,(3,8)这条边的负载是 6,因为有六条简单路径 2−3−8, 2−3−8−7, 3−8, 3−8−7, 4−3−8, 4−3−8−72-3-8,\ 2-3-8-7,\ 3-8,\ 3-8-7,\ 4-3-8,\ 4-3-8-72−3−8, 2−3−8−7, 3−8, 3−8−7, 4−3−8, 4−3−8−7 路过了 (3,8)。

现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。

输入格式

第一行包含两个整数 N,QN,QN,Q,表示星球的数量和操作的数量。星球从 111 开始编号。

接下来的 QQQ 行,每行是如下两种格式之一:

A x y 表示在 xxx 和 yyy 之间连一条边。保证之前 xxx 和 yyy 是不联通的。

Q x y 表示询问 (x,y)(x,y)(x,y) 这条边上的负载。保证 xxx 和 yyy 之间有一条边。

输出格式

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

样例

样例输入

8 6

A 2 3

A 3 4

A 3 8

A 8 7

A 6 5

Q 3 8

样例输出

6

数据范围与提示

对于所有数据,\(1≤N,Q≤100000\)

题解

\(Link-Cut\ Tree\)维护子树信息

不仅仅维护实儿子

还需要维护虚儿子

就相当于在原树中的儿子数量啦

我也不知道为什么

。。。

以后知道了就补一下

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 120000
#define lson (t[x].ch[0])
#define rson (t[x].ch[1])
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Node
{
int ch[2],ff;
int rev,size,sum;
}t[MAX];
int S[MAX],top;
int n,Q;
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void pushup(int x){t[x].sum=t[lson].sum+t[rson].sum+t[x].size+1;}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
pushup(y);pushup(x);
}
void pushdown(int x)
{
if(!t[x].rev)return;
swap(lson,rson);
if(lson)t[lson].rev^=1;
if(rson)t[rson].rev^=1;
t[x].rev^=1;
}
void Splay(int x)
{
S[top=1]=x;
for(int i=x;!isroot(i);i=t[i].ff)S[++top]=t[i].ff;
while(top)pushdown(S[top--]);
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=t[x].ff)Splay(x),t[x].size+=t[rson].sum-t[y].sum,t[x].ch[1]=y,pushup(x);}
void makeroot(int x){access(x);Splay(x);t[x].rev^=1;}
void split(int x,int y){makeroot(x);access(y);Splay(y);}
void cut(int x,int y){split(x,y);t[y].ch[0]=t[x].ff=0;pushup(y);}
void link(int x,int y){makeroot(x);makeroot(y);t[x].ff=y;t[y].size+=t[x].sum;pushup(y);}
int findroot(int x){makeroot(x);while(lson)x=lson;return x;}
int main()
{
n=read();Q=read();
char ch[2];int u,v;
while(Q--)
{
scanf("%s",ch);u=read(),v=read();
if(ch[0]=='A')link(u,v);
else split(u,v),printf("%lld\n",1ll*t[u].sum*(t[v].sum-t[u].sum));
}
return 0;
}
上一篇:344. Reverse String【easy】


下一篇:Angular 个人深究(五)【外部包引用 Leaflet 简单实用】