zoukankan      html  css  js  c++  java
  • BZOJ3832 Rally

    传送门(权限)

    题目大意

    给定一个有向无环图,可以删去一个点和所有与它相连的边,使得图的其余部分最长路径最小,求这个位置和最小的最长路径长度。

    题解

    对于每一条边$u ightarrow v$,设$F_u$表示从任意位置出发到达$u$的最多边数,设$G_v$表示从$v$出发到达任意位置的最多边数,那么最长链即为$max{F_u+G_v+1}$。

    考虑删掉点$x$。

    对于字拓扑序在$x$之前的$y$,那么一定有一条链长度为$F_y$,拓扑序在$x$之后的$y$一定有一条长度为$G_y$的链。对于拓扑序和$x$属于并列关系的$y$,和它相邻的所有边一定$(u ightarrow v)$,其中$u=y$或$v=y$,显然存在$F_u+G_v+1$的链。

    那么按照拓扑序处理每一个点,维护一个集合$S$表示当前有效的链。

    初始时$S$只用所有$G_x$,按照顺序拓扑序序枚举点$x$,然后删去它新失效的边是所有$(u ightarrow x)$的边的$F_u+G_x+1$以及$G_x$,这时集合内的元素的最大值就是最长链的长度。然后删去它之后生效的边是所有$(x ightarrow v)$的$F_x+G_v+1$,因为要确保接下来的拓扑序相互并列的两个点能够相互更新,不难发现删去所有它的后继节点后这些$x ightarrow v$的$F_x+G_v+1$会自行删除。

    在所有的答案中取最小值顺便记录位置即可。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define M 500020
    using namespace std;
    const int BS=(1<<20)+5; char Buffer[BS],*HD,*TL;
    char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    int read(){
    	int nm=0,fh=1; char cw=Getchar();
    	for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    int n,m,fs[M][2],nt[M<<1][2],to[M<<1][2],otd[M][2];
    int q[M],hd,tl,,ans,pos,tmp,dis[M][2];
    priority_queue<int> Q,D;
    inline void rw(){while((!D.empty())&&D.top()==Q.top()) Q.pop(),D.pop();}
    #define del(a) D.push(a),rw()
    #define ins(a) Q.push(a)
    #define tp Q.top()
    void link(int x,int y){
    	nt[tmp][0]=fs[x][0],nt[tmp][1]=fs[y][1],otd[x][0]++,otd[y][1]++;
    	to[tmp][0]=y,to[tmp][1]=x,fs[x][0]=fs[y][1]=tmp,tmp++;
    }
    int DP(int x,int kd){
    	if(!otd[x][kd]) return 0; if(dis[x][kd]) return dis[x][kd];
    	for(int i=fs[x][kd];i!=-1;i=nt[i][kd]) dis[x][kd]=max(dis[x][kd],DP(to[i][kd],kd));
    	++dis[x][kd]; return dis[x][kd];
    }
    int main(){
    	n=read(),m=read(),memset(fs,-1,sizeof(fs)),ans=n-1,pos=1;
    	for(int i=1;i<=m;i++){int x=read(),y=read();link(x,y);}
    	for(int i=1;i<=n;i++) DP(i,0),DP(i,1),ins(dis[i][0]);
    	for(int i=1;i<=n;i++) if(!otd[i][1]) q[tl++]=i;
    	while(hd<tl){
    		int x=q[hd++],maxn; del(dis[x][0]);
    		for(int i=fs[x][1];i!=-1;i=nt[i][1]) del(dis[to[i][1]][1]+dis[x][0]+1);
    		maxn=tp; if(maxn<ans) ans=maxn,pos=x; ins(dis[x][1]);
    		for(int i=fs[x][0];i!=-1;i=nt[i][0]){
    			ins(dis[to[i][0]][0]+dis[x][1]+1);
    			if(!(--otd[to[i][0]][1])) q[tl++]=to[i][0];
    		}
    	}printf("%d %d
    ",pos,ans);	return 0;
    }
    

      

  • 相关阅读:
    雅礼集训 Day6 T2 Equation 解题报告
    雅礼集训 Day6 T1 Merchant 解题报告
    雅礼集训 Day5 T3 题 解题报告
    雅礼集训 Day3 T2 u 解题报告
    雅礼集训 Day3 T2 v 解题报告
    set-begin
    set-constructors
    set-constructors
    list-unique
    list-unique
  • 原文地址:https://www.cnblogs.com/OYJason/p/9865703.html
Copyright © 2011-2022 走看看