题目链接:https://www.zhixincode.com/contest/17/problem/K?problem_id=258
题目大意:一个树上每个点有一个权值,给定一个定点,两条路径的交的全集为这个点,求这两条路径的补的权值最大值
挺裸的一个树形dp,做完差不多的就开始怼欧拉回路了,没来得及看。。
dp[x]表示到root(即给定的点),经过x,当前获得的最大收益,最后的ans就是取至少1个,至多4个这样的路径收益(其交只有这一个定点)
首先需要规定dp的方向,规定一个初始的root,肯定不能跨过root再dp,到了root就该停。
状态转移方程:dp[u]=max(dp[儿子])+val[u]
最后需要和0取max
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=100005;
vector<int>g[maxn];
ll bit[35],dp[maxn];
ll val[maxn];
int n,k;
const ll inf =((ll)1)<<31;
//dp转移方程:dp[u]=max(dp[儿子])+val[u]
void dfs(int u,int far)
{
dp[u]=-1;
for(int i=0;i<g[u].size();i++)
{
int now=g[u][i];
if(now!=far)//不能朝他爹的方向dp
{
dfs(now,u);
dp[u]=max(dp[u],dp[now]);
}
}
dp[u]=max(dp[u],(ll)0);
dp[u]+=val[u];
}
int main()
{
bit[0]=1;
for(int i=1;i<=30;i++)
{
bit[i]=bit[i-1]<<1;
}
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>k;
if(k==0)
{
val[i]=0;
continue;
}
int sig=k>0?1:-1;
val[i]=sig*bit[abs(k)-1];
}
//for(int i=1;i<=5;i++)cout<<val[i]<<' ';cout<<endl;
int u,v;
for(int i=1;i<=n-1;i++)
{
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
int K,q;
cin>>K;
while(K--)
{
priority_queue<ll>qq;
cin>>q;
for(int i=0;i<g[q].size();i++)
{
int now=g[q][i];
dfs(now,q);//以q为根,从q的所有直接连接的node开始dp
qq.push(dp[now]);
}
ll res=val[q];
int fl=4;
while(fl--&&!qq.empty()&&qq.top()>0)
{
res+=qq.top();
qq.pop();
}
//cout<<res<<endl;
int flag=res>0?1:0;
string s="";
while(res)
{
s+=(res%2)?'1':'0';
res/=2;
}
if(!flag)cout<<'-';
for(int i=s.size()-1;i>=0;i--)cout<<s[i];
cout<<endl;
}
return 0;
}