CF325C - Monsters and Diamonds

发布时间 2023-05-16 17:18:52作者: jucason_xu

我们首先考虑建图。我们把每个点向它的所有变换连边,把每个变换往它产出的所有点连边,同时点到变换的边有边权,就是变换中 \(-1\) 的个数。

我们首先处理最小值。我们发现,没有出度的点和变换可以一开始就有结果。只要一个点有一个变换是可以有结果的,这个点就可以有结果。变换则不然,必须所有点都有结果,变换才有结果。

同时最小化结果一定不会跑一整个环,所以我们可以用类似 \(Dijkstra\) 的拓扑排序,用一个堆维护目前的最小答案变换或者点。对于变换,直接对其所在的点更新。对于点,对它所在的所有变换增加贡献,减少度数,一旦度数到 \(0\) 就更新点。

这样,我们就用一个 \(Dijkstra\) 和拓扑排序结合起来的做法完成了最小值的计算和判断一个数能不能有结果。这里的复杂度明显是对的,因为没有负权,并且每个点只会被一个更新到。

我们把所有没有出路的点和变换删掉,剩下的点都是能得到结果的。考虑再做一次拓扑排序,因为这里要求最大值,所以点也是等所有出边都更新完了再更新。那么就是标准的拓扑排序了。同时如果一个点不被更新,它就能到达环,并且是有出路的环(因为没有出路的点都被删掉了),也就满足了 \(-2\) 的要求。

如此做两次,就可以通过了,复杂度 \(O((n+m)\log (n+m))\)

const int P=314000000;
int ans1[200005],ans2[200005],n,m,a[400005],k,b;
int val[400005],deg[400005],dis[400005];
int del[400005];
vt<int>v[200005],vv[200005];
inline void solve1(){
	rp(i,n)ans1[i]=ans2[i]=-1;
	priority_queue<pii>q;
	rp(i,m){
		deg[a[i]]++;
		deg[i+n]=v[i].size();
	}
	rp(i,n+m)del[i]=1;
	rp(i,n)dis[i]=P+1;
	rep(i,n+1,n+m)dis[i]=val[i];
	rp(i,n+m)if(!deg[i]){
		q.push({-dis[i],i});
	}
	while(q.size()){
		int x=q.top().second,y=-q.top().first;
		q.pop();del[x]=0;
		if(y>dis[x])continue;
		if(x<=n){
			ans1[x]=dis[x],ans2[x]=-2;
			for(auto i:vv[x]){
				dis[i+n]+=dis[x],deg[i+n]--;
				dis[i+n]=min(dis[i+n],P);
				if(!deg[i+n])q.push({-dis[i+n],i+n});
			}
		}else{
			int y=a[x-n];
			if(dis[y]>dis[x]){
				dis[y]=dis[x];
				q.push({-dis[y],y});
			}
		}
	}
}
inline void solve2(){
	queue<int>q;
	rp(i,n+m)deg[i]=0,dis[i]=0;
	rp(i,m)if(!del[i+n]){
		deg[a[i]]++;
		for(auto j:v[i])if(!del[j])deg[i+n]++;
	}
	rp(i,n+m)if(!deg[i]&&!del[i]){
		q.push(i);
	}
	while(q.size()){
		int x=q.front();q.pop();
		if(x<=n){
			ans2[x]=dis[x];
			for(auto i:vv[x])if(!del[i+n]){
				dis[i+n]+=dis[x],deg[i+n]--;
				dis[i+n]=min(dis[i+n],P);
				if(!deg[i+n])q.push(i+n);
			}
		}else{
			int y=a[x-n];
			dis[y]=max(dis[y],dis[x]+val[x]);
			dis[y]=min(dis[y],P),deg[y]--;
			if(!deg[y])q.push(y);
		}
	}
	rp(i,n)cout<<ans1[i]<<" "<<ans2[i]<<endl;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>m>>n;
	rp(i,m){
		cin>>a[i]>>k;
		rp(_,k){
			cin>>b;
			if(b==-1)val[i+n]++;
			else {
				v[i].pb(b);
				vv[b].pb(i);
			}
		}
	}
	solve1();
	solve2();
	return 0;
}
//Crayan_r