[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)

Posted rikurika

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)相关的知识,希望对你有一定的参考价值。

bzoj luogu

题意可能会很绕

一句话:基环树的直径。

求直径:

对于环上每一个点记录其向它的子树最长路径为$dp_x$

之后记录环上边长前缀和$ns_i$

dp值为$max_i,jdp[i]+sum[i]+dp[j]-sum[j]$

$dp[j]-sum[j]$提出来进单调队列。

O(n)。

记得dfs改bfs。

技术图片
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long lint;
const int N=1145141;
template<typename TP>inline void read(TP &kk)
    TP ret=0,f=1;char ch=getchar();
    while(ch<0||ch>9)if(ch==-)f=-1;ch=getchar();
    while(ch>=0&&ch<=9)ret=ret*10+ch-0;ch=getchar();
    kk=ret*f;

int n;
struct sumirekoint to,ne,w;e[N*2];
int he[N],ecnt;
void addline(int f,int t,int w)

    e[++ecnt].to=t;
    e[ecnt].w=w;
    e[ecnt].ne=he[f];
    he[f]=ecnt;

bool vv[N],onr[N];
int rnd[N*2],hp,sp,nw[N*2];
lint ns[N*2];

int find(int x,int f)

    if(vv[x])sp=x;return 1;
    vv[x]=1;int tmp;
    for(int i=he[x],t;i;i=e[i].ne)
    
        t=e[i].to;
        if(i==((f&1)?f+1:f-1)) continue;
        if(tmp=find(t,i))
        
            if(tmp==1)
            
                rnd[++hp]=x;
                onr[x]=1;
                nw[hp]=e[i].w;
                if(x!=sp) return 1;
            
            return 2;
        
    
    return 0;

lint dp[N],ans0,ans1;
int h,l;
int st[N];
bool use[N];
int fa[N];
void bfs(int u)

    h = 1,l = 0;
    st[++l] = u;
    use[u]=1;
    while(h<=l)
    
        u = st[h++];
        for(int j=he[u];j;j=e[j].ne)
        
            int to = e[j].to;
            if(use[to]||onr[to])continue;
            use[to] = 1;
            fa[to] = u;
            st[++l] = to;
        
    
    for(int i=l;i>=1;i--)
    
        u = st[i];
        for(int j=he[u];j;j=e[j].ne)
        
            int to = e[j].to;
            if(onr[to]||to==fa[u])continue;
            lint tmp = dp[to]+e[j].w;
            ans0 = max(ans0,dp[u]+tmp);
            dp[u]=max(dp[u],tmp);
        
    

lint ans;
int qu[N*2],qh,qt;
void fuck(int xx)

    ans0=ans1=0;
    hp=0;
    find(xx,0);
    int x;
    for(int i=1;i<=hp;i++)
    
        x=rnd[i];
        bfs(x);
        nw[i+hp]=nw[i];
        rnd[i+hp]=rnd[i];
    
    for(int i=1;i<=2*hp;i++) ns[i]=ns[i-1]+nw[i];
    qh=1,qt=0;
    for(int i=1;i<2*hp;i++)
    
        while(qh<qt&&qu[qh]+hp<=i) qh++;
        if(qh<=qt)ans1=max(ans1,dp[rnd[i]]+ns[i]+dp[rnd[qu[qh]]]-ns[qu[qh]]);
        while(qh<=qt&&dp[rnd[qu[qt]]]-ns[qu[qt]]<=dp[rnd[i]]-ns[i]) qt--;
        qu[++qt]=i;
        
    ans+=max(ans0,ans1);
    hp=0;


int xi,yi,wi;
signed main()

    read(n);
    for(int i=1;i<=n;i++)
    
        read(xi),read(wi);
        addline(i,xi,wi),addline(xi,i,wi);
    
    for(int i=1;i<=n;i++) if(!use[i]) fuck(i);
    printf("%lld\n",ans);
    return 0;
View Code

 

以上是关于[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1791: [Ioi2008]Island 岛屿基环树+单调队列优化dp

岛屿(bzoj1791)

IOI2008 island

IOI2008 Island 岛屿

[IOI2008]Island

[题解] LuoguP4381 [IOI2008]Island