10月2日考试题解(待更新)
Posted 812-xiao-wen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10月2日考试题解(待更新)相关的知识,希望对你有一定的参考价值。
10月2日考试题解
$ T1 $ :
题意简述:
给一棵 $ n $ 个节点的树,点有非负权值,你需要找出两条点不相交的路径,使它们长度和最大。
$ n\le 10^5 $
$ solution: $
有直径的性质可知,最终两条路径只有两种情况:
- 两条路径其中一条为直径
- 两条路径都有一个端点为直径端点
于是我们两遍 $ DFS $ 找到一条直径,并记录这条直径。将这条直径标记(删掉),从直径的每个点开始向直径两边树型 $ DP $ ,找到从直径上每个点出发的最长链,以及不与直径相交的最长链(这个最长连和直径构成初始答案)。然后枚举直径上每一个点作为拐点(一条路径从这里离开直径),找到另一个最优的拐点,更新答案!
$ code: $
ll ans,tot;
int n,tt,rt,id,mx;
ll a[100005];
ll d[100005];
ll s[100005];
ll v[100005];
int t[100005];
bool vis[100005];
struct su
int to,next;
b[200005];
int tou[100005],top;
inline void dfs(int i) //找直径
vis[i]=1; if(d[i]>d[mx]) mx=i;
for(rg j=tou[i];j;j=b[j].next)
rg to=b[j].to; if(vis[to])continue;
d[to]=d[i]+a[to]; dfs(to);
vis[i]=0;
inline bool find(int i,int x) //开栈记录最长链
vis[i]=1; t[++tt]=i; if(i==x) return 1;
for(rg j=tou[i];j;j=b[j].next)
rg to=b[j].to; if(vis[to])continue;
d[to]=d[i]+a[to]; if(find(to,x))return 1;
vis[i]=0; --tt; return 0; //vis数组会保留对直径的标记
inline void dp(int i) //找到从每个点出发的最长链
vis[i]=1; d[i]=0;
for(rg j=tou[i];j;j=b[j].next)
rg to=b[j].to; if(vis[to])continue;
dp(to); tot=max(tot,d[to]+d[i]+a[i]); //tot记录不与直径交的最长链
d[i]=max(d[i],d[to]);
vis[i]=0; d[i]+=a[i]; tot=max(tot,d[i]);
int main()
n=qr();
for(rg i=1;i<=n;++i) a[i]=qr();
for(rg i=1;i<n;++i)
rg x=qr(),y=qr();
b[++top]=suy,tou[x]; tou[x]=top;
b[++top]=sux,tou[y]; tou[y]=top;
d[1]=a[1]; dfs(1); rt=mx; mx=0; //找直径端点
d[rt]=a[rt]; dfs(rt); id=mx; mx=0; //找直径
find(rt,id); //标记直径
for(rg i=1;i<=tt;++i)
rg x=t[i]; s[i]=d[x];
for(rg j=tou[x];j;j=b[j].next) //从直径每个点出发
rg to=b[j].to; if(vis[to])continue;
dp(to); v[i]=max(v[i],d[to]); //树型dp
ans=tot+s[tt]; tot=0;
for(rg i=1;i<=tt;++i) //计算最终答案
ans=max(ans,tot-s[i-1]+v[i]+s[tt]);
tot=max(tot,s[i]+v[i]);
printf("%lld\n",ans);
return 0;
$ T2 $ :
题意简述:
$ solution: $
$ code: $
$ T3 $ :
题意简述:
$ solution: $
$ code: $
以上是关于10月2日考试题解(待更新)的主要内容,如果未能解决你的问题,请参考以下文章