BZOJ3832Rally题解
一道思维神题....
我们像网络流一样加入原点S,与汇点T
用f[i]表示原点到i的最长路,用g[i]表示i到汇点的最长路
f数组与g数组都可以dp求出来的
接下来考虑如何通过这些信息来维护删除某个点的最长路
用拓扑序来删点
我们先将所有g数组加入一个集合中,
每次删点是就先将所有该点的入边的点的f[i]+g[x]从集合中删掉
然后此时集合中最大值就是删除这个点的最优解
然后再将每个点的出边i的f[x]+g[i]加入集合中
可以发现这个集合可以用堆来维护
# include<iostream> # include<cstdio> # include<cmath> # include<cstring> # include<algorithm> # include<queue> using namespace std; const int mn = 500005; struct Grap{ struct edge{int to,next;}; edge e[mn*2]; int head[mn],edge_max; void add(int x,int y) { e[++edge_max].to=y; e[edge_max].next=head[x]; head[x]=edge_max; } }A,B; int deg[mn*2],n,m,a[mn*2]; int f[mn*2],g[mn*2]; void topolpgy() { int tail=1,head=0; for(int i=1;i<=n;i++) if(!deg[i]) a[++head]=i; //printf("%d %d\n",tail,head); while(tail<=head) { int u=a[tail]; tail++; for(int i=A.head[u];i;i=A.e[i].next) { deg[A.e[i].to]--; if(!deg[A.e[i].to]) a[++head]=A.e[i].to; } } } struct Heap{ int heap[mn*2],mark[mn*2],top; void ins(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 del(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]; } }T; int main() { int x,y; A.edge_max=0,B.edge_max=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); A.add(x,y),B.add(y,x); deg[y]++; } topolpgy(); /*for(int i=1;i<=n;i++) printf("%d ",a[i]);*/ int ans=0,ans_len=0x3f3f3f3f; for(int i=1;i<=n;i++) { int u=a[i]; f[u]=max(f[u],1); for(int j=A.head[u];j;j=A.e[j].next) f[A.e[j].to]=max(f[A.e[j].to],f[u]+1); } for(int i=n;i>=1;i--) { int u=a[i]; g[u]=max(g[u],1); for(int j=A.head[u];j;j=A.e[j].next) g[u]=max(g[u],g[A.e[j].to]+1); } /*for(int i=1;i<=n;i++) printf("%d:%d %d\n",i,f[i],g[i]);*/ for(int i=1;i<=n;i++) T.ins(g[i]); T.ins(0); for(int i=1;i<=n;i++) { int u=a[i]; for(int j=B.head[u];j;j=B.e[j].next) { T.del(f[B.e[j].to]+g[u]); //printf("%d ",f[B.e[j].to]+g[u]); } //printf("\n"); T.del(g[u]); if(T.Top()<ans_len) { ans_len=T.Top(),ans=u; //printf("%d ",T.Top()); } for(int j=A.head[u];j;j=A.e[j].next) { T.ins(f[u]+g[A.e[j].to]); //printf("%d ",f[u]+g[B.e[j].to]); } T.ins(f[u]); //printf("%d\n",ans_len-1); } printf("%d %d",ans,ans_len-1); return 0; }