1. 程式人生 > 其它 >7311. 【2021.10.18NOIP提高組模擬】葡萄莊園

7311. 【2021.10.18NOIP提高組模擬】葡萄莊園

Description

\(n\le 10^5,m\le 2\times 10^5\)

Solution

由於顏色只有 3 個,考慮將圖分層。

統計出不走某個顏色的情況下,每個節點所處的聯通塊。

那麼改變顏色可以認為是在某個節點同時走兩個聯通塊。

預處理答案,列舉節點,統計所處的三個聯通塊兩兩聯通的價值,注意去重(可以用 \(\text{map}\),也可以排序)。

同時維護每個連通塊與別的連通塊連線的最優情況。

對於詢問的 \(x\),找出所處的三個連通塊中最優情況價值最大的,即為答案。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 200005
#define ll long long
using namespace std;
int n,m,q,x,y,z,tot,num,sum,len,cir[N][5];
ll a[N],size[N*3],f[N*3];
struct node
{
	int to,next,head,cl;
}edge[M<<1];
struct circ
{
	int id,x,y;
	ll v;	
}c[N*3],d[N*3];
void add(int x,int y,int z)
{
	edge[++tot].to=y;
	edge[tot].cl=z;
	edge[tot].next=edge[x].head;
	edge[x].head=tot;
}
void dfs(int x,int c)
{
	size[num]+=a[x];
	for (int i=edge[x].head;i;i=edge[i].next)
	{
		int v=edge[i].to;
		if (edge[i].cl==c) continue;
		if (cir[v][c]) continue;
		cir[v][c]=num;
		dfs(v,c);
	}
}
bool cmp(circ x,circ y)
{
	if (x.x<y.x) return true;
	if (x.x>y.x) return false;
	return x.y<y.y;
}
int main()
{
	freopen("grape.in","r",stdin);
	freopen("grape.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i)
		scanf("%lld",&a[i]);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	for(int j=1;j<=3;++j)
		for (int i=1;i<=n;++i)
			if (!cir[i][j]) cir[i][j]=++num,dfs(i,j);
	for (int i=1;i<=n;++i)
	{
		x=cir[i][1];y=cir[i][2];z=cir[i][3];
		c[++sum].x=x;c[sum].y=y;c[sum].v=size[x]+size[y],c[sum].id=i;
		c[++sum].x=x;c[sum].y=z;c[sum].v=size[x]+size[z],c[sum].id=i;
		c[++sum].x=y;c[sum].y=z;c[sum].v=size[y]+size[z],c[sum].id=i;
	}
	sort(c+1,c+sum+1,cmp);
	for (int i=1;i<=sum;++i)
	{
		if (c[i].x!=c[i-1].x||c[i].y!=c[i-1].y)
		{
			if (len) f[d[len].x]=max(f[d[len].x],d[len].v),f[d[len].y]=max(f[d[len].y],d[len].v);
			d[++len].x=c[i].x;
			d[len].y=c[i].y;
			d[len].v=c[i].v-a[c[i].id];
		}
		else d[len].v-=a[c[i].id];
	}//去重並統計答案
	scanf("%d",&q);
	while (q--)
	{
		scanf("%d",&x);
		printf("%lld\n",max(max(f[cir[x][1]],f[cir[x][2]]),f[cir[x][3]]));
	}
	return 0;
}