标签:ch int t2 t1 fa 银河 NOI2002 find 英雄
题解
考点:带权并查集。
设 \(d[x]\) 表示 \(x\) 节点前面的战舰数量,\(s[x]\) 表示以 \(x\) 节点为首的那一列战舰的总数,合并操作如下:
void add(int x,int y)
{
int a=find(x),b=find(y);
fa[a]=b;
d[a]=s[b];
s[b]+=s[a];
s[a]=0;
}
把 \(a\) 接到 \(b\),\(a\) 前面的就是 \(s[b]\),然后战舰的总数加 \(s[a]\),而 \(a\) 又不作为头,所以清零。
查询操作:
int find(int x)
{
if(fa[x]==x)return x;
int t1=fa[x],t2=find(fa[x]);
fa[x]=t2;
d[x]+=d[t1];
return fa[x];
}
因为我们进行了路径压缩,设 \(t1\) 为 \(x\) 原来的父亲,\(t2\) 为 \(x\) 现在的父亲,则 \(d[t1]\) 已经计算正确,然后 \(d[x]\) 就加上 \(d[t1]\)。
Code:
#include<bits/stdc++.h>
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=30000;
int fa[N+100],s[N+100],d[N+100];
int find(int x)
{
if(fa[x]==x)return x;
int t1=fa[x],t2=find(fa[x]);
fa[x]=t2;
d[x]+=d[t1];
return fa[x];
}
void add(int x,int y)
{
int a=find(x),b=find(y);
fa[a]=b;
d[a]=s[b];
s[b]+=s[a];
s[a]=0;
}
int main()
{
for(int i=1;i<=N;i++)fa[i]=i,s[i]=1,d[i]=0;
int n;read(n);
for(int i=1,x,y;i<=n;i++)
{
char c;
cin>>c;read(x);read(y);
if(c=='M')add(x,y);
else
{
if(find(x)!=find(y))printf("-1\n");
else printf("%d\n",abs(d[x]-d[y])-1);
}
}
return 0;
}
标签:ch,int,t2,t1,fa,银河,NOI2002,find,英雄 来源: https://www.cnblogs.com/LAK666/p/16450106.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。