zoukankan      html  css  js  c++  java
  • [POI2014]RAJ(最短路,拓扑排序)

    对于一个点 (x) 如何求答案?

    由于这个图是个有向无环图,可以先拓扑排序一遍,求出每个点的拓扑序,从起点到它的最长路 (d2),从它到终点的最长路 (d1)。(我写代码是这么写的,注意顺序)

    把拓扑序比小 (x) 的点的点集叫 (A),大的叫 (B)。答案就是 (maxlimits_{uin A,vin B}(d2_u+d1_v+w_{(u,v)}))

    发现当 (x) 的拓扑序变大 (1) 时,集合 (A) 会多一个数,集合 (B) 会少一个数。

    可以动态维护最大值。

    时间复杂度 (O(mlog m))

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> PII;
    const int maxn=1000100;
    #define MP make_pair
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline int read(){
        int x=0,f=0;char ch=getchar();
        while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f?-x:x;
    }
    int n,m,el,ans1,ans2=2e9,head[maxn],to[maxn],nxt[maxn],el2,head2[maxn],to2[maxn],nxt2[maxn],deg[maxn],id[maxn],cnt,seq[maxn],q[maxn],h,r,d1[maxn],d2[maxn];
    multiset<int,greater<int> > fuck;
    inline void add(int u,int v){
    	to[++el]=v;nxt[el]=head[u];head[u]=el;
    }
    inline void add2(int u,int v){
    	to2[++el2]=v;nxt2[el2]=head2[u];head2[u]=el2;
    }
    int dfs(int u){
    	if(~d1[u]) return d1[u];
    	for(int i=head[u];i;i=nxt[i]) d1[u]=max(d1[u],dfs(to[i]));
    	return ++d1[u];
    }
    int main(){
    	n=read();m=read();
    	FOR(i,1,m){
    		int u=read(),v=read();
    		add(u,v);add2(v,u);
    		deg[v]++;
    	}
    	MEM(d1,-1);
    	FOR(i,1,n) if(d1[i]==-1) d1[i]=dfs(i);
    	h=1;r=0;
    	FOR(i,1,n) if(!deg[i]) q[++r]=i,seq[id[i]=++cnt]=i;
    	while(h<=r){
    		int u=q[h++];
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			d2[v]=max(d2[v],d2[u]+1);
    			if(!--deg[v]) q[++r]=v,seq[id[v]=++cnt]=v;
    		}
    	}
    	FOR(i,1,n) fuck.insert(d1[i]);
    	FOR(i,1,n){
    		int u;
    		if(i!=1){
    			u=seq[i-1];
    			for(int e=head[u];e;e=nxt[e]){
    				int v=to[e];
    				fuck.insert(d2[u]+1+d1[v]);
    			}
    			fuck.insert(d2[u]);
    		}
    		u=seq[i];
    		for(int e=head2[u];e;e=nxt2[e]){
    			int v=to2[e];
    			multiset<int,greater<int> >::iterator it=fuck.find(d2[v]+1+d1[u]);
    			fuck.erase(it);
    		}
    		multiset<int,greater<int> >::iterator it=fuck.find(d1[u]);
    		fuck.erase(it);
    		if(*fuck.begin()<ans2) ans1=seq[i],ans2=*fuck.begin();
    	}
    	printf("%d %d
    ",ans1,ans2);
    }
    
  • 相关阅读:
    软件工程作业团队作业No.1
    软件工程作业No.5
    软件工程作业No.4
    软件工程作业No.3
    软件工程作业No.2
    java 读写yml文件,修改文件内容保持原格式
    oracle 相关
    git基础从创建仓库开始
    oracle安装过程问题记录
    Java 实现小工具读取文件有多少个单词
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11295993.html
Copyright © 2011-2022 走看看