[IOI2008]Island

谁说胖子不能爱 提交于 2019-12-28 04:16:48

题目链接

首先,我们发现这是一个基环外向树森林,所以我们发现只有两种情况:

1.1.最长路径在一颗子树中。

2.2.最长路径分别在两颗子树中,通过基环相连。

因此,我们考虑首先dfsdfs找到这个环,然后对于环上的点跑dpdp,这样我们就解决了第一个情况。

而对于第二种情况,我们首先破坏为链,发现我们的所求就是:

我们定义g[i]g[i]表示以ii为根的外向树的最长路径。

f[x]=mini=xn+1x1(g[i]+g[x]+dis[i,x])f[x]=min_{i=x-n+1}^{x-1}(g[i]+g[x]+dis[i,x])

由于我们发现dis[i,j]=dis[i,k]+dis[k,j]dis[i,j]=dis[i,k]+dis[k,j],所以这个一定可以使用单调队列进行优化。

考虑写成:

f[x]=mini=xn+1x1(g[i]+g[x]+dis[x]dis[i])f[x]=min_{i=x-n+1}^{x-1}(g[i]+g[x]+dis[x]-dis[i])

发现只与g[i]dis[i]g[i]-dis[i]有关,因此我们直接用单调队列优化即可。

代码实现:

//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();
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!