【SHOI2008】cactus仙人掌图

题面

http://darkbzoj.tk/problem/1023

  1. 仙人掌上建有根圆方树(对于方点维护$son[x][i]$和$len[x][i]$,改变$len[x][i]$的定义以规避讨论)
  2. 单调队列维护加入元素和查找最大值的操作。
  3. 其他思路大体上和最短路(http://darkbzoj.tk/problem/2125)一样。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<stack>
#include<vector>
#define ri register int
#define N 100500
using namespace std;

int n,tn,m;
int cir[N];
int a[N];
int ans;

inline int read() {
  int ret=0,f=0; char ch=getchar();
  while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0'&&ch<='9') ret*=10,ret+=ch-'0',ch=getchar();
  return f?-ret:ret;
}

struct tree {
  vector<int> son[N],len[N];
  int f[N];
  void add_edge(int a,int b,int c) {
    son[b].push_back(a);
    len[b].push_back(c);
  }
  void dp(int x) {
    if (!son[x].size()) {
      f[x]=0;
      return;
    }
    for (ri i=0;i<son[x].size();i++) dp(son[x][i]);
    if (x<=tn) {
      f[x]=-1;
      int p=-1;
      for (ri i=0;i<son[x].size();i++) if (f[son[x][i]]>f[x]) f[x]=f[son[x][i]],p=son[x][i];
      if (f[x]>ans) ans=f[x];
      for (ri i=0;i<son[x].size();i++) if (son[x][i]!=p) if (f[x]+f[son[x][i]]>ans) ans=f[x]+f[son[x][i]];
    }
    else {
      f[x]=0;
      int l=son[x].size();
      for (ri i=0;i<l;i++) {
        if (min(cir[x]-len[x][i],len[x][i])+f[son[x][i]]>f[x]) f[x]=min(cir[x]-len[x][i],len[x][i])+f[son[x][i]];
        son[x].push_back(son[x][i]);
        len[x].push_back(cir[x]+len[x][i]);
      }
      deque<int> q;
      while (!q.empty()) q.pop_back();
      for (ri i=0;i<son[x].size();i++) {
        int a=son[x][i],dis=len[x][i];
        while (q.size() && 2*(dis-len[x][q.back()])>cir[x]) q.pop_back();
        if (q.size() && f[a]+f[son[x][q.back()]]+dis-len[x][q.back()]>ans) ans=f[a]+f[son[x][q.back()]]+dis-len[x][q.back()];
        while (q.size() && f[a]-dis>f[son[x][q.front()]]-len[x][q.front()]) q.pop_front();
        q.push_front(i);
      }
    }
  }
} T;

struct graph {
  vector<int> to[N];
  int dfn[N],low[N],cnt;
  int pre[N],dr[N];
  stack<int> s;
  void add_edge(int a,int b) {
    to[a].push_back(b);
    to[b].push_back(a);
  }
  void tarjan(int x) {
    dfn[x]=low[x]=++cnt; s.push(x);
    for (ri i=0;i<to[x].size();i++) {
      int y=to[x][i];
      if (dfn[y]) low[x]=min(low[x],dfn[y]);
      else {
        pre[y]=x; dr[y]=dr[x]+1; tarjan(y);
        if (low[y]>=dfn[x]) {
          ++n;
          cir[n]=dr[s.top()]-dr[x]+1;
          T.add_edge(n,x,0);
          int t;
          do {
            t=s.top(); s.pop();
            T.add_edge(t,n,cir[n]-dr[t]+dr[x]);
          }
          while (t!=y);
        }
        low[x]=min(low[x],low[y]);
      }
    }
  }
} G;

int main() {
  tn=n=read(); m=read();
  for (ri i=1;i<=m;i++) {
    int k=read();
    for (ri j=1;j<=k;j++) a[j]=read();
    for (ri j=2;j<=k;j++) G.add_edge(a[j-1],a[j]);
  }
  G.cnt=0;
  G.tarjan(1);
  T.dp(1);
  printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/shxnb666/p/11076498.html