题意比较明显就不说了。
这题我思考了一会儿,由于题解并不说清楚为什么这样处理的原因,我想了很久才想通= =。
建议看完理解题解以后不要看标,自己独立打出来,这题的思路很妙~。。
首先很容易知道先把原树建出来以后,答案就是(size(fa)-size(x))*size(x)
那么问题是怎么样处理询问呢,当然你可以树剖暴力搞,因为我一开始也是这么想的,这里提供一种更优美的解法= =
我们把树建出来以后,在图上建一颗权值线段树(dfs,顺便求出dfs序),同时用并查集去维护添加操作,同时合并权值线段树在并查集中以find(x),find(y)为根的节点。
一开始我并不理解为什么要合并,感觉不合并到时候照样查询啊,只不过会T吧。
事实证明我很naive,因为每次查询的时候我并查集合并完了,他的根已经不是之前的根了,所以必须在并查集合并的同时对权值线段树进行合并= =。
感觉还是说的不是很清楚,看看代码可能理解的更深刻,有什么不懂的在下面评论区留言吧。
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
struct node
{
int x,y,id;
}b[N];
typedef long long ll;
int fa[N],in[N],out[N],dep[N],vis[N];
int n,id,q,x,y,num;
int head[N<<1],next[N<<1],go[N<<1];
int ls[N*20],rs[N*20],root[N*20],size[N*20];
char ch[5];
int tot,cnt;
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline int merge(int x,int y)
{
if (!x)return y;
if (!y)return x;
size[x]+=size[y];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
return x;
}
inline int query(int x,int l,int r,int l1,int r1)
{
int mid=(l+r)>>1;
if (l==l1&&r==r1)return size[x];
if (r1<=mid)return query(ls[x],l,mid,l1,r1);
else if (l1>mid)return query(rs[x],mid+1,r,l1,r1);
else return query(ls[x],l,mid,l1,mid)+query(rs[x],mid+1,r,mid+1,r1);
}
inline void ins(int &x,int l,int r,int v)
{
if (!x)x=++num;
int mid=(l+r)>>1;
if (l==r)
{
size[x]=1;
return;
}
if (v<=mid)ins(ls[x],l,mid,v);
else ins(rs[x],mid+1,r,v);
size[x]=size[ls[x]]+size[rs[x]];
}
inline void dfs(int x,int fa)
{
in[x]=++cnt;
vis[x]=1;
ins(root[x],1,n,cnt);
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)
{
dep[v]=dep[x]+1;
dfs(v,x);
}
}
out[x]=cnt;
}
int find(int x)
{
if (fa[x]!=x)fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
scanf("%d%d",&n,&q);
fo(i,1,q)
{
scanf("%s",ch);
scanf("%d%d",&b[i].x,&b[i].y);
if (ch[0]=='A')
{
b[i].id=1;
add(b[i].x,b[i].y);
add(b[i].y,b[i].x);
}
else b[i].id=2;
}
fo(i,1,n)if (!vis[i])dfs(i,0);
fo(i,1,n)fa[i]=i;
fo(i,1,q)
{
if (b[i].id==1)
{
int x=find(b[i].x),y=find(b[i].y);
if (dep[x]>dep[y])swap(x,y);
root[x]=merge(root[x],root[y]);
fa[y]=x;
}
if (b[i].id==2)
{
int x=b[i].x,y=b[i].y;
if (dep[x]int fa=find(x),v=query(root[fa],1,n,in[x],out[x]);
printf("%lld\n",1ll*(size[root[fa]]-v)*v);
}
}
}