P3573-[POI2014]RAJ-Rally【拓扑排序,二分+树状数组】

情到浓时终转凉″ 提交于 2020-01-30 17:56:19

正题

题目链接:https://www.luogu.com.cn/problem/P3573


题目大意

nn个点mm条边的DAGDAG,删掉一个点使得最长路最短。


解题思路

先跑一遍拓扑排序
dsids_i表示以ii结尾的最长路,dtidt_i表示以ii开头的最长路,用拓扑序+dp可以搞定

定义两个点集SSTT,我们先将所有所有点放入TT集合,并且把dtdt放入一个数据结构里。

然后按照拓扑序枚举从小到大删除哪个点,枚举到的点xx我们把dtxdt_x从数据结构里删除,对于y>xy->x我们可以把dsy+dtx+1ds_y+dt_x+1从数据结构里删除。

然后查询最小值统计答案

之后把dsxds_x和对于x>yx->y我们有dsx+dty+1ds_x+dt_y+1都丢进数据结构里。

这里用树状数组+二分统计答案。

时间复杂度O(nlog2n)O(n\log^2 n)


codecode

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e6+10;
struct node{
	int to,next;
}a[N];
queue<int> q;
int n,m,cnt,ans,id;
int in[N],top[N],ds[N],dt[N],ls[N];
vector<int> init[N];
struct Tree_Array{
	int t[N];
	void Change(int x,int val){
		if(!x) return;
		while(x<=m){
			t[x]+=val;
			x+=lowbit(x);
		}
		return;
	}
	int Ask(int x){
		int ans=0;
		while(x){
			ans+=t[x];
			x-=lowbit(x);
		}
		return ans;
	}
	int Maxs(){
		int z=Ask(m);
		int l=0,r=m;
		while(l<=r){
			int mid=(l+r)>>1;
			if(Ask(mid)==z)r=mid-1;
			else l=mid+1;
		}
		return l;
	}
}T;
void Top_Sort(){
	for(int i=1;i<=n;i++)
		if(!in[i])q.push(i),top[++cnt]=i;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;in[y]--;
			if(!in[y])q.push(y),top[++cnt]=y;
		}
	}
	return;
}
void Get_Dis(){
	for(int i=1;i<=n;i++){
		int x=top[i];
		for(int j=ls[x];j;j=a[j].next){
			int y=a[j].to;
			ds[y]=max(ds[y],ds[x]+1);
		}
	}
	for(int i=n;i>=1;i--){
		int x=top[i];
		for(int j=0;j<init[x].size();j++){
			int y=init[x][j];
			dt[y]=max(dt[y],dt[x]+1);
		}
	}
	return;
}
void Solve(){
	ans=2147483647;
	for(int i=1;i<=n;i++)
		T.Change(dt[i],1);
	for(int k=1;k<=n;k++){
		int x=top[k];
		T.Change(dt[x],-1);
		for(int i=0;i<init[x].size();i++){
			int y=init[x][i];
			T.Change(ds[y]+dt[x]+1,-1);
		}
		int z=T.Maxs();
		if(z<ans) ans=z,id=x;
		T.Change(ds[x],1);
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			T.Change(ds[x]+dt[y]+1,1);
		}
	}
	return;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		a[i].to=y;
		a[i].next=ls[x];
		ls[x]=i;in[y]++;
		init[y].push_back(x);
	}
	Top_Sort();
	Get_Dis();
	Solve();
	printf("%d %d",id,ans);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!