BZOJ 3832 [Poi2014]Rally
2016-11-09 11:02
316 查看
拓扑排序+堆
暴力的做法是枚举删掉哪一个点,然后DP出删掉这个点之后的最长链长度。那么我们来挖掘一下删点之后的最长链的性质。
记删点为x,记所有能走到x的点集为S1, 所有x能走到的点集为S2,注意到最长链上可能存在一些点属于S1或S2,同时也一定存在一些点既不属于S1,也不属于S2!(反证法)
于是我们考虑能不能通过这些既不属于S1也不属于S2的点来找到当前最长链,这启发我们应该把最长链信息记录在中间,记在边上,而不是最长链的底端。
建源点S和汇点T,考虑割。则割集中一定会存在一条边属于最长链!于是我们在每一条边上记录通过这条边的最长链长度,用堆维护一个割集,按照拓扑序加点并且改变割集即可。
暴力的做法是枚举删掉哪一个点,然后DP出删掉这个点之后的最长链长度。那么我们来挖掘一下删点之后的最长链的性质。
记删点为x,记所有能走到x的点集为S1, 所有x能走到的点集为S2,注意到最长链上可能存在一些点属于S1或S2,同时也一定存在一些点既不属于S1,也不属于S2!(反证法)
于是我们考虑能不能通过这些既不属于S1也不属于S2的点来找到当前最长链,这启发我们应该把最长链信息记录在中间,记在边上,而不是最长链的底端。
建源点S和汇点T,考虑割。则割集中一定会存在一条边属于最长链!于是我们在每一条边上记录通过这条边的最长链长度,用堆维护一个割集,按照拓扑序加点并且改变割集即可。
#include<cstdio> #include<algorithm> #define N 500005 #define M 1000005 #define cmax(u,v) (u)<(v)?(u)=(v):0 #define cmin(u,v) (u)>(v)?(u)=(v):0 using namespace std; namespace ziqian { struct Heap { int heap[M], tot, mark[M]; void Insert(int x) { if(mark[x]){mark[x]--;return;} heap[++tot] = x; for(int i = tot, j = i>>1; j; i=j, j>>=1) { if(heap[j] < heap[i])swap(heap[i], heap[j]); else break; } } void Delete(int x) { mark[x]++; } void Pop() { heap[1] = heap[tot--]; for(int i = 1, j = i<<1; j <= tot; i = j, j <<= 1) { if(heap[j] < heap[j|1] && j < tot) j|=1; if(heap[j] > heap[i])swap(heap[j], heap[i]); else break; } } int Top() { while(mark[heap[1]])mark[heap[1]]--,Pop(); return tot?heap[1]:1; } }heap; struct edge{int next,to;}e[M<<2]; int n, m, ecnt, last , _last , q , in_deg , pos , f , g , ans = N, ans_pos; void addedge(int a, int b) { e[++ecnt] = (edge){last[a], b}; last[a] = ecnt; e[++ecnt] = (edge){_last[b], a}; _last[b] = ecnt; } void Topo_Sort() { int head=1, tail=1; for(int i = 1; i <= n; i++) if(!in_deg[i]) { q[tail] = i; ++tail; } for(; head<tail; head++) { int x = q[head]; pos[head] = x; for(int i = last[x]; i; i=e[i].next) { int y = e[i].to; in_deg[y]--; if(!in_deg[y])q[tail++] = y; } } } void main() { scanf("%d%d",&n,&m); for(int i = 1, a, b; i <= m; i++) { scanf("%d%d",&a,&b); addedge(a,b); in_deg[b]++; } Topo_Sort(); ans_pos=1; for(int i = 1; i <= n; i++) { addedge(0,i); addedge(i,n+1); } for(int i = 0; i <= n+1; i++) for(int j = _last[q[i]]; j; j=e[j].next) cmax(f[q[i]], f[e[j].to]+1); for(int i = n+1; i >= 0; i--) for(int j = last[q[i]]; j; j=e[j].next) cmax(g[q[i]], g[e[j].to]+1); for(int i = last[0]; i; i=e[i].next) { int y = e[i].to; heap.Insert(g[y]); } for(int h = 1; h <= n; h++) { int x = pos[h]; for(int i = _last[x]; i; i=e[i].next) { int y = e[i].to; heap.Delete(f[y] + g[x]); } int top = heap.Top(); if(top < ans)ans = top, ans_pos = x; for(int i = last[x]; i; i=e[i].next) { int y = e[i].to; heap.Insert(f[x] + g[y]); } } printf("%d %d\n",ans_pos,ans-1); } } int main() { ziqian::main(); }
相关文章推荐
- 【图论-拓扑序】BZOJ3832 [Poi2014]Rally
- bzoj 3832: [Poi2014]Rally
- bzoj 3832: [Poi2014]Rally(线段树+拓扑排序)
- 【BZOJ】3832: [Poi2014]Rally
- BZOJ3832 : [Poi2014]Rally
- BZOJ 3832 Poi2014 Rally 拓扑排序+堆
- BZOJ 3832 [Poi2014] Rally 拓扑排序
- BZOJ3832: [Poi2014]Rally
- [BZOJ3832][Poi2014]Rally(拓扑序+线段树)
- BZOJ3832: [Poi2014]Rally
- 【bzoj3832】【poi2014】【Rally】【拓扑排序+线段树】
- BZOJ3832: [Poi2014]Rally
- BZOJ3832[Poi2014] Rally
- BZOJ3832: [Poi2014]Rally
- BZOJ 3832 POI2014 Rally
- bzoj 3832: [Poi2014]Rally 线段树+拓扑排序
- 【bzoj 3832】: [Poi2014]Rally
- 【bzoj 3832】 [Poi2014] Rally (权值线段树+拓扑排序)
- BZOJ 3832: [Poi2014]Rally拓扑排序
- bzoj3524: [Poi2014]Couriers(主席树)