Loading

【题解】[CCO2021] Travelling Merchant

先考虑 \(-1\) 的情况,显然没有出边的点是 \(-1\),将这样的点和对应的边删掉,直到每个点都有出边。显然被删掉的点都是 \(-1\),其余的点都不是 \(-1\)

对于剩下的边,显然 \(r_i\) 最大的边如果走了,那么其他的边随便走,所以对应的 \(+p_i\) 没有意义。我们直接删掉这条边,然后在起始点 \(a_i\) 打上 \(r_i\) 的标记表示到达这里后且资产 \(\ge\) 标记可以直接结束。

删掉边后 \(a_i\) 可能没有出边了,这又回到 \(-1\) 的情况,将对应的点和边删掉,然后找 \(r_i\) 最大的边删掉。最后将所有边删掉。

每个点的标记就是答案。

这道题的关键在于逆向思维和归纳法,如果顺着模拟非常困难,但是从结束时的边入手则非常清晰。每次删除一条边归纳下去也是关键。

#define N 200005
int n, m, deg[N], u[N], v[N];
struct edge{
	int u, v, w, c, op;
	bool operator<(const edge o)const{return w > o.w;}
}a[N], b[N];
vector<int>e[N];
queue<int>q;
int main(){
	//int T = read();while(T--)solve();
	n = read(), m = read();
	rp(i, m)
		deg[a[i].u = read()]++, a[i].v = read(), a[i].w = read(), a[i].c = read(), 
		a[i].op = i, b[i] = a[i], e[a[i].v].pb(i);
	rp(i, n)if(!deg[i])q.push(i);
	memset(u, 0x3f, sizeof(u));
	while(!q.empty()){
		int x = q.front();
		u[x] = ~0, q.pop();
		go(y, e[x]){
			deg[b[y].u]--, v[y] = 1;
			if(!deg[b[y].u])q.push(b[y].u);
		}
	}
	sort(a + 1, a + m + 1);
	rp(i, m){
		if(v[a[i].op])continue;
		cmn(u[a[i].u], a[i].w), deg[a[i].u]--, v[a[i].op] = 1;
		if(!deg[a[i].u]){
			q.push(a[i].u);
			//cout<<"ss "<<a[i].u<<" "<<endl;
			while(!q.empty()){
				int x = q.front();q.pop();
				go(y, e[x])if(!v[y]){
					deg[b[y].u]--, v[y] = 1;
					cmn(u[b[y].u], max(b[y].w, u[x] - b[y].c));
					if(!deg[b[y].u])q.push(b[y].u);
				}
			}
		}
	}
	rp(i, n)printf("%d ",u[i]);el;
	return 0;
}

posted @ 2021-08-24 23:15  7KByte  阅读(294)  评论(0编辑  收藏  举报