首页 > 其他分享 >CF325C - Monsters and Diamonds

CF325C - Monsters and Diamonds

时间:2023-05-16 17:22:18浏览次数:50  
标签:CF325C rp 变换 int del Diamonds dis Monsters deg

我们首先考虑建图。我们把每个点向它的所有变换连边,把每个变换往它产出的所有点连边,同时点到变换的边有边权,就是变换中 \(-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

标签:CF325C,rp,变换,int,del,Diamonds,dis,Monsters,deg
From: https://www.cnblogs.com/jucason-xu/p/17406252.html

相关文章

  • Codeforces Round 850 (Div. 2, based on VK Cup 2022 - Final Round) E. Monsters (h
    传送门详细题解传送门  抄的ygg代码,向在这里说一下刚开始没看懂的部分。  求答案的时候是把所有的当前为止的所有数值加起来减去一个从1开始并且公差为1的等差数列的前size项和。其中size是当前最多能用到哪个位置,满足前size项能构成1,2,3,....,sz这样的形式。  假设我们......
  • C. Monsters (hard version)
    C.Monsters(hardversion)思路最终肯定是一个阶梯的数组,思考怎么维护阶梯,那些数加进来是无用的。用线段树来维护每个数出现的次数。代码/*最后形成的一定是一个阶......
  • Circle of Monsters[*1600][暴力][构造]
    CircleofMonsters[*1600][暴力][构造]Problem-C-Codeforces有\(N\)头怪兽,他们围成一个环,顺时针编号\(1,2,3,4,\dots,N\)每一头怪兽都有2个属性,一个是它的生......
  • CF1784C Monsters (hard version) 题解
    为了便于表述,下文中用"数"替代怪物的血量。我们换一种不同于easyversion中的计算答案的方法。我们先还是按照easyversion中的贪心操作来消除,当一个数能通过这种贪......