题目大意:给定一张拓扑图,要求删掉一个点使最长链最小,求删掉的点以及删掉后的最长链
这题真是神思路- -
首先我们建立源点和汇点 源点连向所有点 所有点连向汇点
那么图中最长链就变成了S到T的最长链
然后我们拓扑序DP求出S到每个点的最长链f[x]和每个点到T的最长链g[x]
我们令一条x->y的边的权值为f[x]+g[y]
那么这个图的最长链就转化成了所有边的边权的最大值
更进一步说 是这个图的一个割集中边权的最大值
那么我们的思路基本确定了:枚举删哪个点,用一些数据结构维护删点后割集中点权最大的边
但是这个怎么维护呢?
按照拓扑序删点就行了
令初始S集只有S 所有点和T都在T集
按照拓扑序依次将每个点从T集中删掉,加入S集
首先将这个点的所有入边从数据结构中删掉 此时割集的边权最大值就是删掉这个点的答案
然后再将这个点的所有出边加入数据结构中即可。
至于这个数据结构用什么。。。支持插入,删除,查询最大值,显然用堆就可以了。
跪Gromah,跪Claris
什么?你问我堆怎么删除?……
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1001001 using namespace std; struct abcd{ int to,next; }table[M<<1]; int head[M],_head[M],tot; int n,m,ans,ans_len=0x3f3f3f3f; int degree[M],a[M],f[M],g[M]; void Add(int head[],int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } namespace Heap{ int heap[M],mark[M],top; void Insert(int x) { if(mark[x]) { --mark[x]; return ; } heap[++top]=x; int t=top; while(t>1) { if(heap[t]>heap[t>>1]) swap(heap[t],heap[t>>1]),t>>=1; else break; } } void Delete(int x) { mark[x]++; } void Pop() { heap[1]=heap[top--]; int t=2; while(t<=top) { if( t<top && heap[t+1]>heap[t] ) t++; if(heap[t]>heap[t>>1]) swap(heap[t],heap[t>>1]),t<<=1; else break; } } int Top() { while(mark[heap[1]]) mark[heap[1]]--,Pop(); return heap[1]; } } void Topology_Sort() { static int q[M],r,h; int i; for(i=1;i<=n;i++) if(!degree[i]) q[++r]=i; while(r!=h) { int x=q[++h]; for(i=head[x];i;i=table[i].next) if(!--degree[table[i].to]) q[++r]=table[i].to; } memcpy(a,q,sizeof a); } int main() { using namespace Heap; int i,j,x,y; cin>>n>>m; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); degree[y]++; Add(head,x,y); Add(_head,y,x); } Topology_Sort(); for(j=1;j<=n;j++) { x=a[j]; f[x]=max(f[x],1); for(i=head[x];i;i=table[i].next) f[table[i].to]=max(f[table[i].to],f[x]+1); } for(j=n;j;j--) { x=a[j]; g[x]=max(g[x],1); for(i=head[x];i;i=table[i].next) g[x]=max(g[x],g[table[i].to]+1); } for(i=1;i<=n;i++) Insert(g[i]); Insert(0); for(j=1;j<=n;j++) { x=a[j]; for(i=_head[x];i;i=table[i].next) Delete(f[table[i].to]+g[x]); Delete(g[x]); if(Top()<ans_len) ans_len=Top(),ans=x; for(i=head[x];i;i=table[i].next) Insert(f[x]+g[table[i].to]); Insert(f[x]); } cout<<ans<<' '<<ans_len-1<<endl; return 0; }