[省选联考 2021 A/B 卷] 图函数

考虑到一件事情首先\(u -> u\)是可行的。
所以其实对于\(f(u,G')\) 只要考虑\([1,u]\)的点。
那么考虑其条件等价于\(u -> i\)\(i -> u\) 都不经过\([1,u)\)的点。
不然我们显然可以构造出一种情况,使得在路径上某个点被删掉。

那么考虑我们对全局进行一个答案的求。
考虑我们设\(g(x,y)\) 满足给定条件。
那么接着考虑我们的这个边的条件。
我们只要求出这个\(i -> j\)限定只能经过\([k + 1,n]\)这些点的最小值的最大值即可。

直接folyd,O(n^3).
考虑加入一波优化。
我们在限制\(i > lim\)时只更新小于\(lim\)的量即可少一半常数。

#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long 
#define N 1005
#define M 200005

int n,m;
int f[N][N];
int ans[M]; 
int g[M];

int main(){
//	freopen("graph.in","r",stdin);
//	freopen("graph.out","w",stdout);	
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		f[u][v] = i;
	}
	for(int lim = n;lim >= 1;--lim){//点的限制
		for(int i = n;i >= lim + 1;--i)
//		for(int i = 1;i < lim;++i)
		g[std::min(f[lim][i],f[i][lim])] ++ ;
		for(int i = 1;i <= n;++i){
			if(!f[i][lim])continue;
			if(i > lim)
			for(int j = 1;j < lim;++j)
			f[i][j] = std::max(f[i][j],std::min(f[i][lim],f[lim][j]));			
			else
			for(int j = 1;j <= n;++j)
			f[i][j] = std::max(f[i][j],std::min(f[i][lim],f[lim][j]));
		}
	}
	ans[m + 1] = n;
	for(int i = m;i >= 1;i--)
	ans[i] = ans[i + 1] + g[i];
	for(int i = 1;i <= m + 1;++i)
	std::cout<<ans[i]<<" ";
}


posted @ 2021-11-24 17:13  fhq_treap  阅读(57)  评论(0编辑  收藏  举报