BZOJ1023: [SHOI2008]cactus仙人掌图

建出圆方树
像普通找直径那样dp一下
环上的dp要维护一个单调队列

code:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 1e9
using namespace std;

inline void up(int &x,const int &y){if(xinline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 110000;

int n,m;
int em,e[maxn][2];

struct edge{int y,nex;}a[maxn<<1],b[maxn<<1];
int len,fir[maxn],len2,fir2[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
inline void ins2(const int x,const int y){b[++len2]=(edge){y,fir2[x]};fir2[x]=len2;}

vector<int>V[maxn]; int cnt;
int T[maxn],tp;
int did,dfn[maxn],low[maxn];
void tarjan(const int x,const int pre)
{
    dfn[x]=low[x]=++did; T[++tp]=x;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(k!=(pre^1))
    {
        if(!dfn[y])
        {
            tarjan(y,k); down(low[x],low[y]);
            if(low[y]==dfn[x])
            {
                ++cnt; V[cnt].clear(); V[cnt].push_back(x);
                int la=0;
                while(la!=y) V[cnt].push_back(la=T[tp--]);
            }
            else if(low[y]>dfn[x]) tp--;
        }
        else down(low[x],dfn[y]);
    }
}
void build()
{
    for(int i=1;i<=em;i++)
    {
        int x=e[i][0],y=e[i][1];
        if(dfn[x]>dfn[y]) swap(x,y);
        if(low[y]>dfn[x]) ins2(x,y),ins2(y,x);
    }
    for(int i=1;i<=cnt;i++)
    {
        for(int j=0;jint ans=0;
int f[maxn];
int ptop[maxn],ptos[maxn],stop[maxn],stos[maxn];
int q[maxn],head,tail,q2c;
void dp(const int x,const int fa)
{
    f[x]=0;
    if(x<=n)
    {
        for(int k=fir2[x],y=b[k].y;k;k=b[k].nex,y=b[k].y) if(y!=fa)
        {
            dp(y,x); up(ans,f[x]+f[y]+(y<=n?1:0));
            if(y<=n) up(f[x],f[y]+1);
            else up(f[x],f[y]);
        }
    }
    else
    {
        int i=x-n,vis=V[i].size();
        for(int j=1;j1,tail=0; q2c=-1;
        for(int j=1;jwhile(head<=tail&&2*(j-q[head])>V[i].size())
            {
                int temp=f[V[i][q[head]]]+q[head]+V[i].size()-j;
                if(temp>q2c) q2c=temp;
                head++;
            }
            if(head<=tail) up(ans,f[V[i][j]]+f[V[i][q[head]]]+j-q[head]);
            up(ans,f[V[i][j]]+q2c);
            int temp=f[V[i][j]];
            while(head<=tail&&f[V[i][q[tail]]]+j-q[tail]<=temp) tail--;
            q[++tail]=j;
        }
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        em=0;
        len=1; for(int i=1;i<=2*n;i++) fir[i]=0;
        for(int i=1;i<=m;i++)
        {
            int k; scanf("%d",&k); int la=0;
            while(k--) 
            {
                int x; scanf("%d",&x);
                if(la) ins(la,x),ins(x,la),e[++em][0]=la,e[em][1]=x;
                la=x;
            }
        }
        did=cnt=tp=0; for(int i=1;i<=n;i++) dfn[i]=low[i]=0;
        tarjan(1,0);
        len2=0; for(int i=1;i<=2*n;i++) fir2[i]=0;
        build();

        ans=0; dp(1,0);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(BZOJ,DP,仙人掌)