您的位置:首页 > 其它

BZOJ 3832 [Poi2014]Rally

2016-11-09 11:02 316 查看
拓扑排序+堆

暴力的做法是枚举删掉哪一个点,然后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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: