列表

详情


NC14419. 线路规划

描述

Q国的监察院是一个神秘的组织。
这个组织掌握了整个帝国的地下力量,监察着Q国的每一个人。
监察院一共有N个成员,每一个成员都有且仅有1个直接上司,而他只听从其上直接司的命令。其中1号成员是监察院的院长,这个庞然大物的主人。
由于时代的进步,监察院议会决定升级组织的旧式通信器,安装最新的反侦测通信器。
他们拿出了M组线路方案,其中第i组线路方案可以用一个四元组(x[i]、y[i]、k[i]、w[i])描述,表示第x[i]号成员可以安装与y[i]号成员的直接通信线路,费用为w[i];x[i]号成员的上司可以安装与y[i]号成员的上司的直接通信线路,费用为w[i];x[i]号成员的上司的上司可以安装与y[i]号成员的上司的上司的直接通信线路,费用为w[i]; …… ;x[i]号成员的k[i] - 1级上司可以安装与y[i]号成员的k[i] - 1级上司的直接通信线路,费用为w[i]。(这k[i]条线路的费用独立计算)
如果一个集合内部的成员两两之间都可以通过直接或间接的通信线路进行通信,那么这个集合的所有成员可以成立一个特别行动组。
监察院想成立一个成员最多的特别行动组,同时他们想让安装线路的费用之和最小,
所以他们找到了Q国的天命者——你,请你帮助他们规划出最优的线路。

输入描述

第一行为2个正整数N、M。
第二行为N - 1个正整数L[i],第i个正整数表示第i+1个成员的直接上司L[i]。
接下来M行每行四个正整数x[i],y[i],k[i],w[i]。

输出描述

仅一行,为特别行动组成员人数的最大值和在此前提下安装线路的最小费用之和。

示例1

输入:

5 3
1 1 2 2
5 4 3 10
1 3 1 5
2 4 2 3

输出:

5 21

说明:

设(u、v、w)表示一条u到v,费用为w的线路。
则一共有(5、4、10)、(2、2、10)、(1、1、10)、(1、3、5)、(2、4、3)、(1、2、3)共6条线路。
选择第1、4、5、6条线路,可以成立特别行动组{1、2、3、4、5},费用之和为21

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1321ms, 内存消耗: 73564K, 提交时间: 2019-03-01 16:37:45

#include<cstdio>
#include<algorithm>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')w=0,ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
#define ll long long
const int N=3e5+5;
vector<int>E[N];int n,m,lg[N],fa[18][N],ufs[18][N],sz[N],ans1;ll val[N],ans2;
struct node{
	int x,y,k,z;
	bool operator < (const node &b)const
		{return z<b.z;}
}a[N];
void dfs(int u){
	for(int v:E[u]){
		fa[0][v]=u;
		for(int i=1;i<18;++i)fa[i][v]=fa[i-1][fa[i-1][v]];
		dfs(v);
	}
}
int find(int x,int *f){return x==f[x]?x:f[x]=find(f[x],f);}
void solve(int x,int y,int z,int d){
	if(find(x,ufs[d])==find(y,ufs[d]))return;
	int fx=find(x,ufs[d]),fy=find(y,ufs[d]);
	if(sz[fx]>sz[fy])swap(fx,fy);
	ufs[d][fx]=fy;
	if(!d)sz[fy]+=sz[fx],val[fy]+=val[fx]+z;
	else solve(x,y,z,d-1),solve(fa[d-1][x],fa[d-1][y],z,d-1);
}
int getf(int x,int d){
	for(int i=0;i<18;++i)if(d>>i&1)x=fa[i][x];
	return x;
}
int main(){
	n=gi();m=gi();
	for(int i=2;i<=n;++i)E[gi()].push_back(i),lg[i]=lg[i>>1]+1;
	dfs(1);
	for(int i=0;i<18;++i)for(int j=1;j<=n;++j)ufs[i][j]=j;
	for(int i=1;i<=n;++i)sz[i]=1;
	for(int i=1;i<=m;++i)a[i]=(node){gi(),gi(),gi(),gi()};
	sort(a+1,a+m+1);
	for(int i=1;i<=m;++i){
		int x=a[i].x,y=a[i].y,k=a[i].k,z=a[i].z;
		int t=lg[k];
		solve(x,y,z,t);solve(getf(x,k-(1<<t)),getf(y,k-(1<<t)),z,t);
//		for(int j=0;j<18;++j)
//			if(k>>j&1)
//				solve(x,y,z,j),x=fa[j][x],y=fa[j][y];
	}
	for(int i=1;i<=n;++i)
		if(find(i,ufs[0])==i)
			if(sz[i]>ans1)
				ans1=sz[i],ans2=val[i];
			else if(sz[i]==ans1)
				ans2=min(ans2,val[i]);
	printf("%d %lld\n",ans1,ans2);return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1434ms, 内存消耗: 53476K, 提交时间: 2020-03-27 11:54:31

#include<bits/stdc++.h>
using namespace std;
const int maxn=252505;
typedef long long ll;
struct node
{
	int x,y,k,w;
	friend bool operator<(node n1,node n2)
	{
		return n1.w<n2.w;
	}
}edges[maxn];
int p[20][maxn],sz[maxn],fa[20][maxn];
ll cost[maxn];
int Log[maxn];
int find(int k,int x)
{
	return x==p[k][x]?x:p[k][x]=find(k,p[k][x]);
}
void merge(int k,int x,int y,int w)
{
	int f1=find(k,x),f2=find(k,y);
	if(f1!=f2)
	{
		p[k][f1]=f2;
		if(!k)
		{
			sz[f2]+=sz[f1];
			cost[f2]+=cost[f1]+w;
			return;
		}
		merge(k-1,x,y,w);
		merge(k-1,fa[k-1][x],fa[k-1][y],w);
	}
}
int main()
{
	int n,m,x;
	scanf("%d%d",&n,&m);
	sz[1]=1;
	for(int i=2;i<=n;i++)
	scanf("%d",&fa[0][i]);
	for(int i=2;i<=n;i++)
	Log[i]=Log[i>>1]+1,sz[i]=1;
	for(int j=0;j<Log[n];j++)
	for(int i=1;i<=n;i++)
	fa[j+1][i]=fa[j][fa[j][i]];
	for(int j=0;j<20;j++)
	for(int i=1;i<=n;i++)
	p[j][i]=i;
	for(int i=0;i<m;i++)
	cin>>edges[i].x>>edges[i].y>>edges[i].k>>edges[i].w;
	sort(edges,edges+m);
	for(int i=0;i<m;i++)
	{
		int k=Log[edges[i].k];
		merge(k,edges[i].x,edges[i].y,edges[i].w);
		int len=edges[i].k-(1<<k);
		int u=edges[i].x,v=edges[i].y;
		for(int j=k;j>=0;j--)
		{
			if((len>>j)&1) u=fa[j][u],v=fa[j][v];
		}
		merge(k,u,v,edges[i].w);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	if(p[0][i]==i&&(sz[ans]<sz[i]||(sz[ans]==sz[i]&&cost[ans]>cost[i])))
	ans=i;
	printf("%d %lld\n",sz[ans],cost[ans]);
}

上一题