【BZOJ1023】Cactus Diagram (SHOI2008) - Square Tree + DP + Monotonic Queue

Test address: Cactus diagram
practice: This question needs to use a square tree + DP + monotonic queue.
When you see a cactus, you think of a square tree. We can convert the DP on the cactus into the DP on the square tree.
First of all, for the point pairs of LCA on the dots, the distance between them can be directly calculated by the edge weight of the square tree, so this part can be done directly with the DP of the diameter on the tree.
The key is the point pair of LCA on the square point. The intersection of the shortest path between such point pairs and the ring pointed to by the square point is a chain, then this path is divided into two parts: the path in the subtree at a certain point. part and part on the ring. We can find the longest chain length from a point to a subtree by DP, and when dealing with rings, we can use a monotonic queue to optimize the DP processing by analogy to the method of finding the diameter of a ring nested tree, that is, for each point on the ring, find it in it. The maximum point-to-point distance between the subtree of the point and the subtree of this point in the clockwise half-ring length interval. The time complexity of processing a ring in this way is O ( ring long ) , then the time complexity of the entire algorithm is O ( n ) Yes, you can pass this question.
My stupid place: The cactus template I wrote at the beginning was wrong... I don't know why I can drop a question...
The following is my code:

#include <bits/stdc++.h>
using namespace std;
const int N=50010;
const int M=N<<2;
int n,m,tote=0,totpbc,first[N]={0},firsted[N<<1]={0},tot=0,fa[N],ans=0;
int st[N],top=0,dfn[N],low[N],tim=0;
int dp[N<<1]={0},q[N<<1],pos[N<<1],cir[N<<1],h,t;
bool vis[N]={0},inst[N]={0};
struct edge
{
    int v,next,w,id;
}e[M],ed[M];

void insert(int a,int b,int id)
{
    e[++tot].v=b;
    e[tot].next=first[a];
    e[tot].id=id;
    first[a]=tot;
}

void inserted(int a,int b,int w)
{
    ed[++tot].v=b;
    ed[tot].next=firsted[a];
    ed[tot].w=w;
    firsted[a]=tot;
}

void combine(int x,int y)
{
    int now=y;
    cir[0]=0;
    while(now!=x)
    {
        cir[++cir[0]]=now;
        now=fa[now];
    }
    cir[++cir[0]]=x;
    for(int i=1;i<=cir[0];i++) cir[cir[0]+i]=cir[i];
    h=1,t=0;
    for(int i=1;i<=(cir[0]>>1);i++)
    {
        while(h<=t&&dp[q[t]]+pos[t]<=dp[cir[i]]+i) t--;
        q[++t]=cir[i];
        pos[t]=i;
    }
    for(int i=(cir[0]>>1)+1;i<=cir[0]+(cir[0]>>1);i++)
    {
        now=i-(cir[0]>>1);
        while(h<=t&&pos[h]<=now) h++;
        while(h<=t&&dp[q[t]]+pos[t]<=dp[cir[i]]+i) t--;
        q[++t]=cir[i];
        pos[t]=i;
        ans=max(ans,dp[q[h]]+pos[h]+dp[cir[now]]-now);
    }

    inserted(x,++totpbc,0);
    for(int i=1;i<cir[0];i++)
    {
        inserted(totpbc,cir[i],min(i,cir[0]-i));
        dp[totpbc]=max(dp[totpbc],dp[cir[i]]+min(i,cir[0]-i));
    }
}

void tarjan(int v,int laste)
{
    vis[v]=inst[v]=1;
    dfn[v]=low[v]=++tim;
    st[++top]=v;
    int now=top;
    for(int i=first[v];i;i=e[i].next)
        if (e[i].id!=laste)
        {
            if (!vis[e[i].v])
            {
                fa[e[i].v]=v;
                tarjan(e[i].v,e[i].id);
                if (low[e[i].v]>dfn[v])
                {
                    top--;
                    inst[e[i].v]=0;
                    inserted(v,e[i].v,1);
                }
                if (low[e[i].v]==dfn[v])
                {
                    for(int i=top;i>now;i--)
                        inst[st[i]]=0;
                    top=now;
                }
                low[v]=min(low[v],low[e[i].v]);
            }
            else if (inst[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
        }
    for(int i=first[v];i;i=e[i].next)
        if (fa[e[i].v]!=v&&dfn[v]<dfn[e[i].v]) combine(v,e[i].v);
    for(int i=firsted[v];i;i=ed[i].next)
    {
        ans=max(ans,dp[v]+dp[ed[i].v]+ed[i].w);
        dp[v]=max(dp[v],dp[ed[i].v]+ed[i].w);
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int k,last=0,a;
        scanf("%d",&k);
        while(k--)
        {
            scanf("%d",&a);
            if (last) insert(a,last,++tote),insert(last,a,tote);
            last=a;
        }
    }

    totpbc=n;
    tot=0;
    fa[1]=0;
    tarjan(1,0);
    printf("%d",ans);

    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325529688&siteId=291194637