『Raiden Ei』 Round 1B-不动鸣神,恒常乐土题解

题目背景

雷电影小姐喜欢去神樱树下追忆过去。

一日,她看着真化成的神樱,莫名想到了一个有趣的问题。

但她还要回忆往事,所以这个问题便交给了你来解决。

题目描述

影现在手里有 n 个点,每个点都记录了一段往事,有些事件之间会相互联想到,但保证不会从某一个点开始向外联想最终会联想回自己。

由于每件事情对影都有一个重要性,所以每个点都会有一个点权。

影在追忆过去时,想要使回忆到的事情的重要性总和尽可能多。

但是要注意,因为记忆中有许多伤心事,为了避免回忆到的事产生联想,使影伤心,对往事的选择需要满足以下两个条件:

  1. 若选取了一个事件 x,则所有能联想到 x 的事件都不可被选择。

  2. 若未选择事件 x,则最多选择 k 个能联想到 x 的事件。

请你求出在满足上述条件的前提下,影能获得的最大事件重要性总和是多少。

形式化题意:

给定一个 n 个点 m 条边无环图,每个点要么被选且周围的点都不被选,要么自己不被选且周围的点最多选 k 个。

求出所选的点的最大点权和。

输入格式

第一行输入三个正整数 n,m,k,表示事件数目和事件之间的联想数。

第二行输入 n 个整数,其中 Ai​ 表示第 i 个事件的重要性。

接下来 m 行,每行输入两个整数 u,v,表示事件 u 和 v 相互间可以联想到。

输出格式

输出一个整数,表示答案。

输入输出样例

输入 #1复制

6 5 2
7 10 12 50 2 4
1 2
1 3
2 4
2 5
2 6

输出 #1复制

66

输入 #2复制

4 3 1
1 2 3 4
1 2
2 3
3 4

输出 #2复制

5

说明/提示

样例解释:

对于样例一,选择事件 3,4,6 是最优选择。

对于样例二,选择事件 1,4 最优。

数据范围:

本题采用捆绑测试

  • Subtask 1(10 pts):n,m≤10。
  • Subtask 2(20 pts):k≤2。
  • Subtask 3(30 pts):n,m≤103。
  • Subtask 4(10 pts):n,m≤2×105。
  • Subtask 5(30 pts):无特殊限制。

对于所有测试数据,1≤n,m≤106,1≤k≤10,1≤Ai​≤109。

如果出现重边/自环,请忽略。

思路

树型DP,fi0代表选自己,fi1为自己不选选k个儿子,fi2为自己不选选k-1个儿子。

可以发现,fi0为其所有儿子fi2和,fi1为所有儿子fi1+最大k个大于0的fi0-fi1,fi2为所有儿子fi1+最大k-1个大于0的fi0-fi1。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,k,a[1000006],u,vv,f[1000006][3],lk=0;
vector<long long> v[1000006];
bool bo[1000006],bos[1000006];
struct one{
	long long a;
	long long b;
	bool c;
};
bool cmp(long long a1,long long b1){
	return a1>b1;
}
void abc(long long a1,long long fa){
    bo[a1]=1;
    f[a1][0]=a[a1];
	priority_queue<long long> q;
    for(int i=0;i<v[a1].size();i++){
        long long tt=v[a1][i];
        if(tt!=fa){
            abc(tt,a1);
            f[a1][0]+=f[tt][2];
            f[a1][1]+=f[tt][1];
            f[a1][2]+=f[tt][1];
            q.push(1000000000-(f[tt][0]-f[tt][1]));
            if(q.size()>=k+1){
            	q.pop();
			}
        }
    }
    long long lo[10],ol=0;
    while(q.size()>=1){
    	lo[++ol]=1000000000-q.top();
    	q.pop();
	}
	sort(lo+1,lo+ol+1,cmp);
	for(int i=1;i<=min(ol,k);i++){
		//cout<<lo[i]<<" ";
		if(lo[i]>=0){
			f[a1][1]+=lo[i];
		}
		if(lo[i]>=0&&i!=k){
			f[a1][2]+=lo[i];
		}
	}
	//cout<<endl;
    //cout<<a1<<" "<<f[a1][0]<<" "<<f[a1][1]<<" "<<f[a1][2]<<endl;
    return ;
}//0自己选,1自己不选选k个儿子,2k-1个
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        cin>>u>>vv;
        v[u].push_back(vv);
        v[vv].push_back(u);
    }
    for(int i=1;i<=n;i++){
        if(bo[i]==0){
            abc(i,0);
            lk+=max(f[i][0],max(f[i][1],f[i][2]));
        }
    }
    cout<<lk<<endl;
	return 0;
}

posted @ 2025-10-05 19:33  bz02_2023f2  阅读(2)  评论(0)    收藏  举报  来源