[POI2014] RAJ-Rally
阿新 • • 發佈:2018-06-14
radius printf AR 輸入輸出 分享 d+ style sort IV
題目描述
給定一個N個點M條邊的有向無環圖,每條邊長度都是1。
請找到一個點,使得刪掉這個點後剩余的圖中的最長路徑最短。
輸入輸出格式
輸入格式:
第一行包含兩個正整數N,M(2<=N<=500 000,1<=M<=1 000 000),表示點數、邊數。
接下來M行每行包含兩個正整數A[i],Bi,表示A[i]到B[i]有一條邊。
輸出格式:
包含一行兩個整數x,y,用一個空格隔開,x為要刪去的點,y為刪除x後圖中的最長路徑的長度,如果有多組解請輸出任意一組。
輸入輸出樣例
輸入樣例#1:6 5
1 3
1 4
3 6
3 4
4 5
輸出樣例#1: 1 2
考慮怎麽利用有向無環圖這個性質。
假設我們從 x -> y ,其中x的拓撲序為a,y的拓撲序為b,顯然a<b。
那麽顯然a<拓撲序<b的點都不再會被經過了。
所以我們就可以用x -> y這條邊所在的最長路徑來更新刪除 a<拓撲序<b 的點 的答案了。
當然刪除一個點i還不會影響路徑上拓撲序都>或< top(i)的點。
對於前者我們可以在下標是拓撲序的線段樹上直接區間修改;後者直接預處理出前綴後綴就可以了。
(最近好像常數不是很大的樣子)
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=500005; #define lc (o<<1) #define mid (l+r>>1) #define rc ((o<<1)|1) inline int read(){ int x=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; return x; } int hd[maxn],ne[maxn*2],to[maxn*2],num; int dfn[maxn],dy[maxn],F[maxn],B[maxn],dc; int n,m,le,ri,w,mx[maxn*4],d[maxn],p,ans=1<<30; int qz[maxn],hz[maxn]; inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num,d[y]++;} void update(int o,int l,int r){ if(l>=le&&r<=ri){ mx[o]=max(mx[o],w); return;} if(le<=mid) update(lc,l,mid); if(ri>mid) update(rc,mid+1,r); } void dfs(int o,int l,int r,int M){ if(l==r){ M=max(max(M,mx[o]),max(qz[l-1],hz[l+1])); if(M<ans) ans=M,p=dy[l]; return; } dfs(lc,l,mid,max(M,mx[o])); dfs(rc,mid+1,r,max(M,mx[o])); } inline void tpsort(){ queue<int> q; int x; for(int i=1;i<=n;i++) if(!d[i]) q.push(i); while(!q.empty()){ x=q.front(),q.pop(); dfn[x]=++dc,dy[dc]=x; for(int i=hd[x];i;i=ne[i]){ F[to[i]]=max(F[to[i]],F[x]+1); if(!(--d[to[i]])) q.push(to[i]); } } for(int i=dc,now;i;i--){ now=dy[i]; for(int j=hd[now];j;j=ne[j]) B[now]=max(B[now],B[to[j]]+1); } } inline void getnew(){ for(int i=1;i<=n;i++) for(int j=hd[i];j;j=ne[j]){ le=dfn[i]+1,ri=dfn[to[j]]-1; if(le<=ri) w=F[i]+B[to[j]]+1,update(1,1,n); } for(int i=1;i<=n;i++) qz[i]=max(qz[i-1],F[dy[i]]); for(int i=n;i;i--) hz[i]=max(hz[i+1],B[dy[i]]); } inline void solve(){ tpsort(); getnew(); dfs(1,1,n,0); } int main(){ n=read(),m=read(); int uu,vv; for(int i=1;i<=m;i++) uu=read(),vv=read(),add(uu,vv); solve(); printf("%d %d\n",p,ans); return 0; }
[POI2014] RAJ-Rally