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

雷电影小姐喜欢去神樱树下追忆过去。
一日,她看着真化成的神樱,莫名想到了一个有趣的问题。
但她还要回忆往事,所以这个问题便交给了你来解决。
题目描述
影现在手里有 n 个点,每个点都记录了一段往事,有些事件之间会相互联想到,但保证不会从某一个点开始向外联想最终会联想回自己。
由于每件事情对影都有一个重要性,所以每个点都会有一个点权。
影在追忆过去时,想要使回忆到的事情的重要性总和尽可能多。
但是要注意,因为记忆中有许多伤心事,为了避免回忆到的事产生联想,使影伤心,对往事的选择需要满足以下两个条件:
-
若选取了一个事件 x,则所有能联想到 x 的事件都不可被选择。
-
若未选择事件 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;
}

浙公网安备 33010602011771号