标签:time name 第一个 tps enter alt ret hint asc
这道题可以学到很多东西
首先先以环中每个点为根求出最远能到达的距离
然后最长链为环中某两点的距离再加上,这两点最远到达的距离
然后具体怎么求这些东西呢
首先求以环中每个点为根求出最远能到达的距离
我们先标记每个点的入度,若一开始入度为一,则说明此点为叶子节点,然后通过不断向上求,并且不断删掉该点的叶子节点个数,就可以求到环上的点
而最后环上的点必定入度为二,所以可以实现避免环上的点求最远距离,并且可以找出环来
void topsort(){
ll l=1,r=0;
for (ll i=1;i<=n;i++) if(du[i]==1) Q[++r]=i;
while(l<=r){
ll u=Q[l];
for (ll i=adj[u];i;i=bian[i].next){
ll v=bian[i].v;
if(du[v]>1){
d[c[u]]=max(d[c[u]],f[v]+f[u]+bian[i].w);
f[v]=max(f[v],f[u]+bian[i].w);
if((--du[v])==1) Q[++r]=v;
}
}
l++;
}
}
最后求环上的最远距离可以把环拆开复制成两倍做成一条链,便可以用单调队列方法求最值
void getans(ll t,ll x){
ll y=x;
ll i,r,l=0;
ll m=0;
do{
a[++m]=f[y];
du[y]=1;
for (i=adj[y];i;i=bian[i].next){
ll v=bian[i].v;
if(du[v]>1){
b[m+1]=b[m]+bian[i].w;
y=v;
break;
}
}
}while(i);
if(m==2){void getans(ll t,ll x){
ll y=x;
ll i,r,l=0;
ll m=0;
do{
a[++m]=f[y];
du[y]=1;
for (i=adj[y];i;i=bian[i].next){
ll v=bian[i].v;
if(du[v]>1){
b[m+1]=b[m]+bian[i].w;
y=v;
break;
}
for (i=adj[y];i;i=bian[i].next){
if(bian[i].v==x) {b[2]=max(b[2],bian[i].w);}
}
d[t]=max(d[t],f[x]+f[y]+b[2]);
return ;
}
for (i=adj[y];i;i=bian[i].next){
if(bian[i].v==x){
b[m+1]=b[m]+bian[i].w;
break;
}
}
for (i=1;i<m;i++) {a[m+i]=a[i];b[m+i]=b[m+1]+b[i];}
Q[l=r=1]=1;
for (i=2;i<2*m;i++){
while(l<=r&&i-Q[l]>=m) l++;
d[t]=max(d[t],a[i]+a[Q[l]]+b[i]-b[Q[l]]);
while(l<=r&&a[Q[r]]+b[i]-b[Q[r]]<=a[i]) r--;
Q[++r]=i;
}
}
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1000000+10; typedef long long ll; struct my{ int v; int next; ll w; }; my bian[maxn*2]; int adj[maxn],n,c[maxn],du[maxn],Q[maxn*2]; bool vis[maxn]; ll f[maxn],fa,d[maxn],a[maxn*2],b[maxn*2]; void myinsert(ll u,ll v,ll w){ bian[++fa].v=v; bian[fa].next=adj[u]; bian[fa].w=w; adj[u]=fa; du[v]++; } void dfs(ll x,ll t){ c[x]=t; for (ll i=adj[x];i;i=bian[i].next){ ll v=bian[i].v; if(!c[v]){ dfs(v,t); } } } void topsort(){ ll l=1,r=0; for (ll i=1;i<=n;i++) if(du[i]==1) Q[++r]=i; while(l<=r){ ll u=Q[l]; for (ll i=adj[u];i;i=bian[i].next){ ll v=bian[i].v; if(du[v]>1){ d[c[u]]=max(d[c[u]],f[v]+f[u]+bian[i].w); f[v]=max(f[v],f[u]+bian[i].w); if((--du[v])==1) Q[++r]=v; } } l++; } } void getans(ll t,ll x){ ll y=x; ll i,r,l=0; ll m=0; do{ a[++m]=f[y]; du[y]=1; for (i=adj[y];i;i=bian[i].next){ ll v=bian[i].v; if(du[v]>1){ b[m+1]=b[m]+bian[i].w; y=v; break; } }//把环拆成链 }while(i); if(m==2){ for (i=adj[y];i;i=bian[i].next){ if(bian[i].v==x) {b[2]=max(b[2],bian[i].w);} } d[t]=max(d[t],f[x]+f[y]+b[2]); return ; } for (i=adj[y];i;i=bian[i].next){ if(bian[i].v==x){ b[m+1]=b[m]+bian[i].w; break;把环的开头找到、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 } } for (i=1;i<m;i++) {a[m+i]=a[i];b[m+i]=b[m+1]+b[i];} Q[l=r=1]=1; for (i=2;i<2*m;i++){ while(l<=r&&i-Q[l]>=m) l++; d[t]=max(d[t],a[i]+a[Q[l]]+b[i]-b[Q[l]]); while(l<=r&&a[Q[r]]+b[i]-b[Q[r]]<=a[i]) r--; Q[++r]=i; } } int main(){ // freopen("bzoj1791.in","r",stdin); //freopen("bzoj1791.out","w",stdout); scanf("%lld",&n); ll u,w; for (int i=1;i<=n;i++){ scanf("%lld%lld",&u,&w); myinsert(u,i,w); myinsert(i,u,w); } ll t=0; for (ll i=1;i<=n;i++) if(!c[i]) { ++t; dfs(i,t);//标记每棵树 } topsort(); ll ans=0; for(ll i=1;i<=n;i++){ if(du[i]>1&&!vis[c[i]]){ vis[c[i]]=1; getans(c[i],i); ans+=d[c[i]]; } } printf("%lld ",ans); return 0; }
标签:time name 第一个 tps enter alt ret hint asc
原文地址:https://www.cnblogs.com/lmjer/p/9363946.html