Tyvj4878:道路修建 (环套树DP+单调队列)
来源:互联网 发布:笔画笔顺查询软件 编辑:程序博客网 时间:2024/05/16 18:42
题目传送门:http://tyvj.cn/p/4878
题目分析:刚看题以为很简单,想着直接在每一个外向树上跑最长路,再随便搞搞跨环的最长路就行了。然而仔细分析发现跨环的最长路并不是那么好搞,还要用到单调队列优化……
首先外向树上的最长路就和求树的直径一样,以任一点为根DFS,再用深度最大的点为根DFS,第二次DFS的最大深度值即为树的直径;或者也可以用类似DP的写法。再考虑跨环最长路,它一定是环上的某两个点外向树上的最深节点之间的路径,不妨记dep[i]为环上第i个点外向树的深度。然后将环复制一遍,每个点考虑和它前面的
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=3010;struct edge{ int obj; bool flag; edge *Next,*rev;} e[maxn<<2];edge *head[maxn];int cur=-1;int fa[maxn];bool vis[maxn];bool on_ring[maxn];int dep_son[maxn];int max_dep[maxn];int ring[maxn<<1];int f[maxn<<1];int num;int que[maxn<<1];int he,tail;int n,m;void Add(int x,int y){ cur++; e[cur].obj=y; e[cur].flag=true; e[cur].rev=&e[cur+1]; e[cur].Next=head[x]; head[x]=e+cur; cur++; e[cur].obj=x; e[cur].flag=true; e[cur].rev=&e[cur-1]; e[cur].Next=head[y]; head[y]=e+cur;}void Dfs1(int node){ vis[node]=true; for (edge *p=head[node]; p; p=p->Next) if (p->flag) { p->flag=p->rev->flag=false; int son=p->obj; if (vis[son]) { num=1; ring[1]=node; on_ring[node]=true; while (1) { num++; ring[num]=fa[ ring[num-1] ]; on_ring[ ring[num] ]=true; if (ring[num]==son) break; } } else { fa[son]=node; Dfs1(son); } }}void Dfs2(int node,int from){ max_dep[node]=0; for (edge *p=head[node]; p; p=p->Next) { int son=p->obj; if ( !on_ring[son] && son!=from ) { Dfs2(son,node); if (max_dep[son]+1>max_dep[node]) max_dep[node]=max_dep[son]+1,dep_son[node]=son; } }}int Dfs3(int node,int from){ int temp=0; for (edge *p=head[node]; p; p=p->Next) { int son=p->obj; if ( !on_ring[son] && son!=from ) temp=max(temp, Dfs3(son,node)+1 ); } return temp;}void Push(int x){ que[++tail]=x; while (he<tail) { if (f[ que[tail-1] ]>f[ que[tail] ]) break; tail--; que[tail]=que[tail+1]; }}int Work(){ for (int i=1; i<=n; i++) vis[i]=false,on_ring[i]=false,dep_son[i]=0; fa[1]=0; Dfs1(1); int temp=0; for (int i=1; i<=num; i++) { int x=ring[i]; on_ring[x]=false; Dfs2(x,x); int y=x; while (dep_son[y]) y=dep_son[y]; temp=max(temp, Dfs3(y,y) ); on_ring[x]=true; } int mid=num>>1; for (int i=1; i<=mid; i++) ring[num+i]=ring[i]; for (int i=1; i<=num+mid; i++) f[i]=max_dep[ ring[i] ]-i; he=1,tail=0; for (int i=1; i<=mid; i++) Push(i); for (int i=mid+1; i<=num+mid; i++) { while (que[he]<i-mid) he++; temp=max(temp, f[i]+(i<<1)+f[ que[he] ] ); Push(i); } for (int i=1; i<=n; i++) for (edge *p=head[i]; p; p=p->Next) p->flag=true; return temp;}int main(){ freopen("road.in","r",stdin); freopen("road.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) head[i]=NULL; for (int i=1; i<n; i++) { int x,y; scanf("%d%d",&x,&y); Add(x,y); } for (int i=1; i<=m; i++) { int u,v; scanf("%d%d",&u,&v); edge *hu=head[u],*hv=head[v]; Add(u,v); printf("%d\n", Work() ); head[u]=hu,head[v]=hv; } return 0;}
阅读全文
1 0
- Tyvj4878:道路修建 (环套树DP+单调队列)
- Tyvj4878:道路修建(环套树+单调队列)
- [bzoj2435][Noi2011]道路修建(树上dp)
- [BZOJ2435][Noi2011]道路修建(树形dp)
- 【DP】【LIS】道路修建
- 【NOI2011T4】道路修建-树形DP
- BZOJ 2500 幸福的道路 树形DP+单调队列
- 【bzoj2500】幸福的道路 单调队列+树形dp
- 【bzoj2500】【幸福的道路】【树形dp+单调队列】
- 幸福的道路_bzoj2500_树形dp+单调队列
- 【BZOJ2435】【Noi2011】道路修建 树形DP
- bzoj2435: [Noi2011]道路修建 树上dp
- dp单调队列(详解)
- 道路修建
- 道路修建
- CF487B Strip(单调队列预处理+单调队列优化dp)
- noip2009 道路游戏 (单调队列优化动态规划)
- [BZOJ 2500]幸福的道路 树形dp+单调队列+二分答案
- poj 1273 Drainage Ditches
- 9月28日训练日记
- cin慢解决方案
- 编程题目1
- JAVA Socket 编程学习
- Tyvj4878:道路修建 (环套树DP+单调队列)
- 旋转矩阵和变换矩阵
- EA&UML日拱一卒-活动图::14.4 ProtocolStateMachines
- java设计模式之原型模式,如何实现深克隆
- 启动Tomcat的时候报错:java.lang.Cl assCastException: net.sf.cglib.proxy.Enhancer$EnhancerKey$$KeyFactoryByCG
- 智力3
- HDU:Prime Ring Problem
- Codeforces Round #436 (Div. 2)
- 【Leetcode】算法题26 Remove Duplicates from Sorted Array