首先,我们发现这是一个基环外向树森林,所以我们发现只有两种情况:
最长路径在一颗子树中。
最长路径分别在两颗子树中,通过基环相连。
因此,我们考虑首先找到这个环,然后对于环上的点跑,这样我们就解决了第一个情况。
而对于第二种情况,我们首先破坏为链,发现我们的所求就是:
我们定义表示以为根的外向树的最长路径。
由于我们发现,所以这个一定可以使用单调队列进行优化。
考虑写成:
发现只与有关,因此我们直接用单调队列优化即可。
代码实现:
//Optimize
#pragma GCC optimize("Ofast")
//Head File
#include<bits/stdc++.h>
using namespace std;
#define il inline
//Variable
#define ll long long
#define ull unsigned long long
#define db double
#define lb long double
//Debug
#define B cerr<<"Break Point"<<endl;
#define P(x) cerr<<#x<<' '<<"="<<' '<<(x)<<endl;
#define p(x) cerr<<#x<<' '<<"="<<' '<<(x)<<' ';
#define ml(x) cerr<<"Size of array is "<<x*4/1024/1024<<" MB"<<endl;
//Vector
#define vc vector
#define puf push_front
#define pof pop_front
#define pub push_back
#define pob pop_back
#define vbe(x) x.begin(),x.end()
//Memset
#define ms(x) memset(x,0,sizeof(x))
#define MS(x) memset(x,0x3f3f3f3f,sizeof(x))
//Pair
#define fi first
#define se second
//File
#define fin(x) freopen(x,"r",stdin)
#define fou(x) freopen(x,"w",stdout)
void fio()
{
#ifndef ONLINE_JUDGE
freopen("sample.in","r",stdin);
freopen("sample.out","w",stdout);
#endif
}
void pti()
{
double timeuse = clock()*1000.0/CLOCKS_PER_SEC;
cerr<<"Timeuse "<<timeuse<<"ms"<<endl;
}
void end()
{
pti();
exit(0);
}
//Inf
#define INF 0x3f3f3f3f
#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
//IO
namespace io
{
const int SIZ=55;int que[SIZ],op,qr;char ch;
template<class I>
il void gi(I &w)
{
ch=getchar(),op=1,w=0;while(!isdigit(ch)){if(ch=='-') op=-1;ch=getchar();}
while(isdigit(ch)){w=w*10+ch-'0';ch=getchar();}w*=op;
}
template<class I>
il void print(I w)
{
qr=0;if(!w) putchar('0');if(w<0) putchar('-'),w=-w;while(w) que[++qr]=w%10+'0',w/=10;
while(qr) putchar(que[qr--]);
}
}
using io::gi;
using io::print;
const int N=1e6+5;
struct EDGE
{
int to,nxt;
ll w;
};
struct node
{
int t;
ll v;
};
int n,cnt=1,num;
int head[N],c[N*2],anc[N],pre[N];
ll d[N],w[N*2],res1,res2;
bool ins[N],col[N],vis[N],tag[N*2];
EDGE e[N*2];
deque<node>q;
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
e[cnt].w=z;
head[x]=cnt;
}
void dfs(int x)
{
if(ins[x])
{
int cur=anc[x];
assert(cur<=n);
vis[cur]=true,c[++num]=cur,cur=anc[cur];
while(cur!=anc[x])
{
vis[cur]=true,c[++num]=cur,cur=anc[cur];
}
return;
}
ins[x]=true;
for(int i=head[x];i;i=e[i].nxt)
{
if(tag[i]) continue;
tag[i]=tag[i^1]=true;
anc[e[i].to]=x,pre[e[i].to]=i;
dfs(e[i].to);
}
}
void calc(int x)
{
col[x]=true;
for(int i=head[x];i;i=e[i].nxt)
{
if(vis[e[i].to]||col[e[i].to]) continue;
calc(e[i].to);
res1=max(res1,d[x]+d[e[i].to]+e[i].w);
d[x]=max(d[x],d[e[i].to]+e[i].w);
}
}
ll solve(int x)
{
num=0;
dfs(x);
assert(num<=n);
res1=0,res2=0;
for(int i=1;i<=num/2;++i) swap(c[i],c[num-i+1]);
for(int i=1;i<=num;++i)
{
calc(c[i]);
c[i+num]=c[i];
}
for(int i=2;i<=num*2;++i)
{
int v=c[i];
w[i]=w[i-1]+e[pre[v]].w;
}
while(!q.empty()) q.pob();
for(int i=1;i<=num*2;++i)
{
int v=c[i];
while(!q.empty()&&q.front().t<i-num+1) q.pof();
if(!q.empty()) res2=max(res2,d[v]+w[i]+q.front().v);
while(!q.empty()&&q.back().v<=d[v]-w[i]) q.pob();
q.pub({i,d[v]-w[i]});
}
return max(res1,res2);
}
int main()
{
fio();
gi(n);
for(int i=1,x,z;i<=n;++i)
{
gi(x),gi(z);
add(i,x,z),add(x,i,z);
}
ll ans=0;
for(int i=1;i<=n;++i) if(!ins[i]) ans+=solve(i);
print(ans),putchar(10);
end();
}
来源:CSDN
作者:_DAG_
链接:https://blog.csdn.net/CaptainDAG/article/details/103736681