题目描述
有 n 个人,每个人有k个属性值。 定义两个人的疏远度为他们k个属性值的差的绝对值的和。 形式化的说,用 ai,j 表示第i个人的第j个属性值( 1 ≤ i ≤ n,1 ≤ j ≤ k ), 则x和y的疏远度= 。 一开始n个人互不认识,现在有两种事件: 1 x y 表示x和y相互认识了。注意,认识具有传递性,即若a认识b,b认识c,则a认识c。 2 x 表示询问在x和x认识的人当中选出2个人(可以是同一个人),疏远度的最大值。 请你回答每个询问事件。
输入描述:
第一行三个整数n,k,m,分别表示人数,属性个数,事件个数。接下来n行,每行k个整数,第i行第j个数表示 ai,j 。接下来m行,每行描述一个事件,格式见题目描述。
输出描述:
对每个询问事件,输出一行表示答案。
示例1
输入
3 1 5
1
2
4
2 1
1 1 2
2 1
1 2 3
2 1
输出
0
1
3
说明
一开始1,2,3互不认识。第一个事件,询问1,这时要在{1}中选两个人,只能选1和1,疏远度=0。第二个事件,1和2互相认识了。第三个事件,询问1,这时要在{1,2}中选两个人,选出1和2,取得疏远度最大值=|1-2|=1。第四个事件,2和3互相认识了。第五个事件,询问1,这时要在{1,2,3}中选两个人,选出1和3,取得疏远度最大值=|1-4|=3。
备注:
全部的输入数据满足: 1 ≤ n ≤ 105 1 ≤ k ≤ 5 1 ≤ m ≤ 106 1 ≤ ai,j ≤ 109 1 ≤ x,y ≤ n
对于10%的数据,n ≤ 10,m ≤ 10
对于另外10%的数据,n ≤ 1000,m ≤ 1000
对于另外10%的数据,k=1
对于另外20%的数据,k=2
对于另外20%的数据,ai,j ≤ 2
这道题看到认识这两个字能想到并查集。
把他们都变成强连通快然后在根据题目中给的求和公式算出疏远值
在合并S,T的时候新的最大值要么是原来的答案要么是
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long LL;
LL a[N][10],b[N][1<<5],ans=-9999999;
int c[N];
int kk;
int n,k,m;
LL max1(LL x,LL y)
{
if(x<y)
return y;
else
return x;
}
int find(int x)
{
if(x==c[x])
return x;
c[x]=find(c[x]);
return c[x];
}
int join(int x,int y)
{
int x1=find(x);
int y1=find(y);
if(x1==y1)
return 0;
c[y1]=x1;
for(int i=0;i<=kk;i++)
{
b[x1][i]=max1(b[x1][i],b[y1][i]);
}
return 0;
}
int main()
{
int p1,p2,p3;
scanf("%d%d%d",&n,&k,&m);
kk=(1<<k)-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
scanf("%lld",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=0;j<=kk;j++)
for(int p=0;p<k;p++)
{
if(j&(1<<p))
b[i][j]+=a[i][p+1];
else
b[i][j]-=a[i][p+1];
}
for(int i=1;i<=n;i++)
c[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d",&p1);
if(p1==1)
{
scanf("%d%d",&p2,&p3);
join(p2,p3);
}
if(p1==2)
{
ans=-999999999;
scanf("%d",&p2);
int tp=find(p2);
for(int j=0;j<=kk;j++)
ans=max1(ans,b[tp][j]+b[tp][j^kk]);
printf("%lld\n",ans);
}
}
return 0;
}
来源:nkw