Problem
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之间有一条边。
Output
对每个查询操作,输出被查询的边的负载。
Sample Input
8
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
Sample Output
6
Data Constraint
对于100%的数据,1≤N,Q≤100000
Solution
先离线将所有边连一遍,发现原图是一棵树或是一片森林。
我们将所有森林连成一棵树(原来是一棵树的不用),然后进行树链剖分操作。
假设现在我们要加一条边,那么:
①设该边连着的两个点为x,y(deep[x]<deep[y])。
②将以y点为根节点的子树(暂时)的大小加到
For example:
图中的A点就是暂时x点连着的最上面的祖先,假设以y点为根节点的子树大小为delta,那么x到A这一条链就要被区间修改加上delta。
③查询的时候单点查询,所以只有线段树维护的最底层的数据才有效,代表线段树的区间(区间长度
Special
今天一位学长告诉我,C++递归会爆栈的其中一个原因就是C++中每递归一层,在递归内定义的变量又要被重新开一次,导致三万多层递归就爆了。
解决方案有2个:
1.将变量定义到程序开头。
2.在递归中输入static xxxx,这样程序虽然会跑慢一点,但是空间只会被开一次。
这道题目还可以用link-cut-tree来解决,可惜我splay初学。
所以链接待更新。
Code
其实这个代码的树链剖分部分写得并不是很好,还是有许多可以修改的地方。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define eg(i,x) for(i=head[x];i;i=edge[i].next)
#define N 100203
#define LL long long
using namespace std;
struct note{
LL from,to,next;
};note edge[N*2];
LL n,q,m,k,u,v,x,y,i,j,la;
LL l1,r1;
LL ans,tot,t1,t2;
LL gx,gy,tt;
LL head[N],qu[N][3],siz[N],hv[N];
LL f[N],g[N],fa[N],cn[N][2];
LL deep[N],target[N],order[N],top[N];
LL sum[N*20],lazy[N*20];
bool bz[N];
char ch;
void lb(LL x,LL y)
{
edge[++tot].from=x;
edge[tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
}
LL get(LL n)
{
if (f[n]==n) return n;
else
{
f[n]=get(f[n]);
return f[n];
}
}
void dfs(LL x)
{
int i;
bz[x]=1;
eg(i,x)
if (edge[i].to!=fa[x])
{
fa[edge[i].to]=x;
dfs(edge[i].to);
}
}
void dfs1(LL x)
{
int i;
bz[x]=1;
eg(i,x)
if (edge[i].to!=fa[x])
{
deep[edge[i].to]=deep[x]+1;
dfs1(edge[i].to);
fa[edge[i].to]=x;
siz[x]+=siz[edge[i].to];
}
}
void dfs2(LL x,LL tp)
{
top[target[order[x]=++target[0]]=x]=tp;
hv[x]=0;
eg(i,x)
if (edge[i].to!=fa[x] && siz[edge[i].to]>siz[hv[x]]) hv[x]=edge[i].to;
if (hv[x]) dfs2(hv[x],tp);
eg(i,x)
if (edge[i].to!=fa[x] && edge[i].to!=hv[x]) dfs2(edge[i].to,edge[i].to);
}
void build(LL s,LL l,LL r)
{
if (l==r)
{
sum[s]=1;
return;
}
LL wz=(l+r)/2;
build(s*2,l,wz);
build(s*2+1,wz+1,r);
sum[s]=sum[s*2]+sum[s*2+1];
}
void change(LL s,LL l,LL r,LL l1,LL r1,LL delta)
{
if (l==l1 && r==r1)
{
sum[s]+=delta;
lazy[s]+=delta;
return;
}
if (lazy[s])
{
sum[s*2]+=lazy[s];
lazy[s*2]+=lazy[s];
sum[s*2+1]+=lazy[s];
lazy[s*2+1]+=lazy[s];
lazy[s]=0;
}
LL wz=(l+r)/2;
if (r1<=wz) change(s*2,l,wz,l1,r1,delta);
else if (l1>wz) change(s*2+1,wz+1,r,l1,r1,delta);
else
{
change(s*2,l,wz,l1,wz,delta);
change(s*2+1,wz+1,r,wz+1,r1,delta);
}
sum[s]=sum[s*2]+sum[s*2+1];
}
LL find(LL s,LL l,LL r,LL x)
{
if (l==r) return sum[s];
if (lazy[s])
{
sum[s*2]+=lazy[s];
lazy[s*2]+=lazy[s];
sum[s*2+1]+=lazy[s];
lazy[s*2+1]+=lazy[s];
lazy[s]=0;
}
LL wz=(l+r)/2;
if (x<=wz) return find(s*2,l,wz,x);
else return find(s*2+1,wz+1,r,x);
sum[s]=sum[s*2]+sum[s*2+1];
}
void area_ch(LL x,LL y)
{
LL x1,y1;
while (1)
{
x1=top[x];
y1=top[y];
if (deep[x1]<deep[y1])
{
swap(x,y);
swap(x1,y1);
}
if (x1==y1) break;
change(1,1,n,order[x1],order[x],g[gy]);
x=fa[x1];
}
if (order[x]>order[y]) swap(x,y);
change(1,1,n,order[x],order[y],g[gy]);
}
int main()
{
scanf("%lld%lld\n",&n,&q);
fo(i,1,n) f[i]=i,g[i]=siz[i]=1;
fo(i,1,q)
{
scanf("%c%lld%lld\n",&ch,&u,&v);
qu[i][0]=u;qu[i][1]=v;
if (ch=='A')
{
lb(u,v);lb(v,u);qu[i][2]=0;
} else qu[i][2]=1;
}
fo(i,1,n)
if (!bz[i])
{
dfs(i);
if (la) cn[++tt][0]=la;cn[tt][1]=i;
la=i;
}
fo(i,1,tt) lb(cn[i][0],cn[i][1]),lb(cn[i][1],cn[i][0]);
dfs1(1);
dfs2(1,1);
build(1,1,n);
fo(i,1,q)
{
if (!qu[i][2])
{
gx=get(qu[i][0]);
gy=get(qu[i][1]);
if (gx!=gy)
{
if (deep[gx]>deep[gy])
{
swap(gx,gy);
swap(qu[i][0],qu[i][1]);
}
area_ch(gx,qu[i][0]);
g[gx]+=g[gy];g[gy]=0;
f[gy]=gx;
}
} else
{
if (deep[qu[i][0]]>deep[qu[i][1]]) swap(qu[i][0],qu[i][1]);
gx=get(qu[i][0]);
t1=find(1,1,n,order[gx]);
t2=find(1,1,n,order[qu[i][1]]);
t1-=t2;
ans=t1*t2;
printf("%lld\n",ans);
}
}
}