牛客练习赛78:
注意数组的头和尾在实际模拟时的情形
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn],dp[maxn],n,m,x1,up[maxn],ans,sum,vis[maxn],d,b[maxn],k,t;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
scanf("%d",&x1);
if(x1!=b[k])b[++k]=x1;
}
for(int i=1;i<=k;i++){
int x=b[i];
if(!vis[x]){
dp[++d]=x;
ans+=sum;
sum+=a[x];
vis[x]=1;
}
else{
int s=0,t=0;
up[dp[d]]=a[x];
for(int j=d;j>=1;j--){
up[dp[j]]=up[dp[j+1]]+a[dp[j+1]];
if(dp[j]==x){
s=j;
break;
}
t+=a[dp[j]];
}
for(int j=s;j<d;j++){
dp[j]=dp[j+1];
}
dp[d]=x;
ans+=t;
up[x]=0;
}
}
printf("%d\n",ans);
}
//29
C : CCA的子树
题意:
要选出两个节点,满足任意一个不是另一个的祖先节点,最大化以两个节点为根的子树的点权和 。
如果选不出两棵合法的子树,则输出“Error”。
思路:
从根节点1出发,我们可以找到左边子树的最大值与右边子树的最大值,二者一定可以保证不存在公共的祖先,并且满足了找左右最大值的要求,我们如果找到了这样的两棵子树那么就把他们更新一下答案。
并且在左右子树中也同样是这样的问题,我们依次往下即可求解正确的答案。
现在仅仅是把树形结构从二叉树变化成了多叉树,那么同样的道理就是在多个儿子中间找到最大的两个儿子,如果只有一个儿子就不能更新答案。并且返回包含节点在内的最大子树点。
这里判断只有单链一种情况,如果你把答案初始化到代表无穷小的话,可能会出现这样的数据把你卡掉,这道题目并没有考虑到。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll inf=-1e10;
const int maxn=5e6+5;
ll a[maxn],n,vis[maxn],ans=inf,to[maxn],head[maxn],nex[maxn],k;
void add(int x,int y){
to[++k]=y;
nex[k]=head[x];
head[x]=k;
}
int dfs(int u,int f){
int x=0,max1=0,max2=0;
for(int i=head[u];i;i=nex[i]){
int y=to[i];
if(y==f)continue;
int he=dfs(y,u);//找权值最大的子树节点号
a[u]+=a[y];//当前节点的所有子树权值和
if(max1==0||a[max1]<a[he])max2=max1,max1=he;//更新最大子节点:先把最大子节点给次节点,再更新最大子节点
else if(max2==0||a[max2]<a[he])max2=he;//直接更新次大子节点
}
if(max2!=0)//包含max1!=0,更新ans
ans=max(ans,a[max1]+a[max2]);//更新ans,最大子树权值+次大子树权值
if(max1==0||a[u]>a[max1])max1=u; // 当前树子树更新完毕后,继续向上传递,
//当前根节点变成子节点,可以被选用
return max1;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs(1,0);
if(ans!=inf)printf("%lld\n",ans);
else printf("Error\n");
}