BZOJ 1023: [SHOI2008]cactus仙人掌图(仙人掌DP)
2018-03-13 10:46
513 查看
题意
求仙人掌直径仙人掌直径:任意两点间最短路的最大值。
说两句
仙人掌DP包括所有仙人掌题目都是要抓住那个简单环,讨论在环上和不在环上或者是环的根和不是环的根的情况。如果可能的话尽可能向树的方向靠拢,因为树非常特殊。
具体实现其实主要就差不多是个tarjan算法了。
在有些复杂的时候可能需要先DFS预处理出仙人掌的双亲结点,父亲儿子这些,但是像这种比较简单的题目就没必要预处理。
还有就一般不要妄想在环的根上记录个什么,因为它可能是很多环的根。不过在环的根上不算环的时候,它就只能在一个环上。
分析
树上的贪心是错的,因此做DP类似树的DP
考虑树的情况,对于一个结点取最长的子树和次长的子树合并。
对于仙人掌上面的‘不是环的根’的点,可以有相同的方法(但是注意不要把父亲结点和母亲结点算进去了)。
对于结点是环的根的情况:在环上取两个点然后分别取这两个点的最长子树+两点最短路。
实现
非环上的代码很简单,用low数组和fa数组可判断是不是双亲结点。在环上的情况我们需要遍历整个环来统计答案,好在每条边最多属于一个简单环,因此均摊时间复杂度还是O(1)的。
1、在环的根结点可以找到环的最后一个结点,就找到了环。
2、提出这个环之后,破环+单调队列,这样可以顺便保证最短路。
代码
#include<cmath> #include<queue> #include<cctype> #include<cstdio> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=5e4+105,maxm=2*maxn; int np,first[maxn]; struct edge{ int to,next; }E[maxm<<1]; void add(int u,int v) { E[++np]=(edge){v,first[u]}; first[u]=np; } int T,n,m,ans; int dfs_clock,dfn[maxn],low[maxn],f[maxn],fa[maxn],dep[maxn]; void Init() { int k,u,v; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d",&k); scanf("%d",&u); for(int i=2;i<=k;i++) { scanf("%d",&v); add(u,v); add(v,u); u=v; } } } int a[maxn<<1]; int q[maxn<<1],front,rear; void solve(int rt,int y) { int cnt=dep[y]-dep[rt]+1; for(int i=y;i!=rt;i=fa[i]) a[cnt--]=f[i]; a[cnt]=f[rt]; cnt=dep[y]-dep[rt]+1; for(int i=1;i<=cnt;i++)a[i+cnt]=a[i]; front=rear=0; q[rear++]=1; for(int i=2;i<=2*cnt;i++) { while(rear>front && i-q[front]>cnt/2)front++; if(rear>front)ans=max(ans,i+a[i]+a[q[front]]-q[front]); while(rear>front && a[q[rear-1]]-q[rear-1]<=a[i]-i)rear--; q[rear++]=i; } for(int i=2;i<=cnt;i++) f[rt]=max(f[rt],a[i]+min(i-1,cnt-i+1)); } void DFS(int i,int ff,int d) { dep[i]=d,fa[i]=ff; dfn[i]=low[i]=++dfs_clock; for(int p=first[i];p;p=E[p].next) { int j=E[p].to; if(j==ff)continue;//有没有重边不影响结果 if(dfn[j]) { low[i]=min(low[i],dfn[j]); continue; } DFS(j,i,d+1); low[i]=min(low[i],low[j]); if(low[j]>dfn[i]) { ans=max(ans,f[i]+f[j]+1); f[i]=max(f[i],f[j]+1); } } for(int p=first[i];p;p=E[p].next) { int j=E[p].to; if(fa[j]!=i && dfn[i]<dfn[j])solve(i,j); } } int main() { Init(); DFS(1,0,1); printf("%d\n",ans); return 0; }
相关文章推荐
- [BZOJ1023][SHOI2008][仙人掌直径][队列优化DP]cactus仙人掌图
- BZOJ1023[SHOI2008]cactus仙人掌图 【仙人掌DP】
- [仙人掌直径 单调队列 DP] BZOJ 1023 [SHOI2008]cactus仙人掌图
- [BZOJ1023][SHOI2008[Cactus仙人掌]][Tarjan+单调队列+树形DP]
- BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
- BZOJ 1023 [SHOI2008]cactus仙人掌图 DP+单调队列
- [bzoj1023][SHOI2008]cactus仙人掌图【仙人掌】
- 【DP】 BZOJ 1023: [SHOI2008]cactus仙人掌图
- 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)
- BZOJ 1023: [SHOI2008]cactus仙人掌图 | 在仙人掌上跑DP
- bzoj1023 [SHOI2008]cactus仙人掌图 树形DP+单调队列
- BZOJ 1023 [SHOI2008]cactus仙人掌图
- 【BZOJ 1023】【SHOI 2008】cactus仙人掌图
- bzoj 1023: [SHOI2008]cactus仙人掌图
- bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图
- BZOJ1023 [SHOI2008]cactus仙人掌图
- 【BZOJ】【1023】【SHOI2008】cactus仙人掌图
- bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列
- bzoj 1023: [SHOI2008]cactus仙人掌图
- bzoj1023: [SHOI2008]cactus仙人掌图