[Ybt high-efficiency advanced 3-4-4] the brightness of stars

The brightness of the star

Topic link: ybt efficient advanced 3-4-4

General idea

There are some stars, and each star has brightness.

Give the relative relationship of the brightness of some stars, and ask how big the sum of the brightness of these stars is at least.

The dimmest brightness of a star is 1 11 . The larger the value, the brighter.

The relationship has two equal brightness, one is brighter or darker than the other, and one is not brighter or darker than the other.

Ideas

First of all, there is a small pit, that is, not greater than is actually less than or equal to, and not less than is greater than or equal to, don't get the other way around.

Then we would think if AAA brightness is less thanBBB , thatBBThe brightness of B can beA + 1 A+1A+1 , if it is less than or equal to, it isAAA .
If there are multiple such conditions, in order to satisfy all of them, we have to choose the one with the greatest brightness.

If it is the same, then it is the same.

Because you can push it all from one place.
But there are also greater than and greater than or equal, so if you want to do it directly, you can't determine the brightness of the initial point.
Then we consider converting it into less than and less than or equal to.

If AAA is greater thanBBB , which is actually equivalent toBBB is less thanAAA .
IfAAA is greater than or equal toBBB , which is actually equivalent toBBB is less than or equal toAAA

The next question is how to determine the initial point at the beginning.

Then you will find it has a ring.
That makes the ring become acyclic. . .
Tarjan shrink it!

How to shrink it, we consider AAA is less than or less than or equal toBBB with one fromAAA toBBThe directed edge of B. Then the ones that are condensed together have the same brightness.
Then you will think that if an edge in a ring is made of less than, then there is a problem. (Because you also require the same brightness, and then you can't make the brightness the same in this place, then there is a contradiction)
Then you divide the edges into two categories, the ones that can participate in the reduction and those that cannot.
Then you also shrink the point normally (otherwise it cannot become a DAG), and then when building the image after the shrink point, if one edge cannot participate in the shrink point, but its two sides belong to the same after the shrink point, it is a contradiction. There is no solution.

Then you will find that DAG may have more than one starting point, but the problem is not big, so set the brightness to 1 11 Will it be all right soon.
Then you will think of using topological order DP, and then when you transfer, judge the type of the edge you transfer, if it is less than the original+ 1 +1+ 1 , otherwise it is the original.
(Because you want the smallest sum)
(I just add one without thinking at first, it's only70 707 0 points)

Then it's ok, you can look at the code for specific implementation.

Code

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

struct node {
    
    
	int to, nxt, cc;
}e[1000001], e_[1000001];
ll ans;
int le_[100001], KK_;
int n, m, le[100001], KK, in[100001];
int op, x, y, dfn[100001], tmp, tot, ru[100001];
int low[100001], sta[100001], num[100001], dis[100001];
queue <int> q;

void add(int x, int y, int cc) {
    
    //原来的图
	e[++KK] = (node){
    
    y, le[x], cc}; le[x] = KK;
}

void add_(int x, int y, int cc) {
    
    //缩点后的图
	e_[++KK_] = (node){
    
    y, le_[x], cc}; le_[x] = KK_;
}

void tarjan(int now) {
    
    //Tarjan 缩点
	dfn[now] = low[now] = ++tmp;
	sta[++sta[0]] = now;
	
	for (int i = le[now]; i; i = e[i].nxt)
		if (!dfn[e[i].to]) {
    
    
			tarjan(e[i].to);
			low[now] = min(low[now], low[e[i].to]);
		}
		else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
	
	if (dfn[now] == low[now]) {
    
    
		in[now] = ++tot;
		num[tot] = 1;
		while (sta[sta[0]] != now) {
    
    
			num[tot]++;
			in[sta[sta[0]]] = tot;
			sta[0]--;
		}
		sta[0]--;
	}
}

int main() {
    
    
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; i++) {
    
    
		scanf("%d %d %d", &op, &x, &y);
		
		if (op == 1) {
    
    //亮度相等,直接连缩点的边
			add(x, y, 0);
			add(y, x, 0);
			continue;
		}
		if (op == 2) {
    
    //小于,连不可以缩点的边
			add(x, y, 1);
			continue;
		}
		if (op == 3) {
    
    //A 不小于 B,就是 A 大于等于 B,又可以是 B 小于等于 A,连可以缩点的边
			add(y, x, 0);
			continue;
		}
		if (op == 4) {
    
    //A 大于 B,相当于 B 小于 A,那就连可以缩点的边
			add(y, x, 1);
			continue;
		}
		if (op == 5) {
    
    //A 不大于 B,就是小于等于,连小于等于的边
			add(x, y, 0);
			continue;
		}
	}
	
	for (int i = 1; i <= n; i++)//缩点
		if (!dfn[i]) tarjan(i);
	
	for (int i = 1; i <= n; i++)
		for (int j = le[i]; j; j = e[j].nxt)
			if (in[i] != in[e[j].to]) {
    
    //连不同点之间的边
				add_(in[i], in[e[j].to], e[j].cc);
				ru[in[e[j].to]]++;//统计入度,到时拓扑用
			}
			else if (e[j].cc) {
    
    //不能缩点的边用来缩点了,则无解
				printf("-1");
				return 0;
			}
	
	for (int i = 1; i <= tot; i++)
		if (!ru[i]) q.push(i), dis[i] = 1;
	while (!q.empty()) {
    
    //拓扑序 DP 求每个的亮度
		int now = q.front();
		q.pop();
		
		ans += 1ll * dis[now] * num[now];//记得亮度加进总亮度之间要乘这个点包含点的个数
		
		for (int i = le_[now]; i; i = e_[i].nxt) {
    
    
			ru[e_[i].to]--;
			dis[e_[i].to] = max(dis[e_[i].to], dis[now] + e_[i].cc);
			//如果这个边是小于,那 cc 值就是 1,亮度也至少要加一
			//如果这个边是小于等于,那 cc 值就是 0,亮度可以不用加,跟之前一样
			//刚好符合,我们就不用新开变量,用这个 cc 值就好了
			if (!ru[e_[i].to]) {
    
    
				q.push(e_[i].to);
			}
		}
	}
	
	printf("%lld", ans);
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114232092