noi.ac NA537 【Graph】

本来以为过了...然后FST了...

吐槽:nmdGraph为什么不连通...

这题想法其实非常\(na\ddot{\imath}ve\),就是对于一个连通块先钦点一个点为根,颜色是\(1\),考虑到边权限制点权,可以做二分图染色,钦点连通块内的某个形如树形的边的子集是全部合法的,显然一棵树是一定有解的,对于此时的\(\min ,\max\)只需要看根节点的取值范围取\(\min ,\max\),对于图的话显然就是多了一些边,判断多的边两端节点是否同色,如果同色则意味着根节点的权值是唯一确定的,如果不是整数则无解,否则直接赋值重跑一遍计算\(ans\)即可,复杂度\(\mathcal{O}(n+m)\)

因为代码是从FST的改过来的,memset其实会T,但是懒得改了,所以下面代码复杂度是假的,不过不影响正确性

#include<bits/stdc++.h>
#define yes printf("%lld %lld\n",ansa,ansb);exit(0)
#define no printf("NIE\n");exit(0)
#define int long long

using namespace std;

signed ch;

void qread(int &xx){
	xx=0;ch=getchar();
	while(!isdigit(ch)){
		ch=getchar();
	}
	while(isdigit(ch)){
		xx=xx*10+ch-'0';
		ch=getchar();
	}
}

const int N=5e5+5,M=6e6+6;

int n,m,ans,ansa,ansb,p[N],vis[N];

int fir[N],nxt[M],to[M],edge[M],cntedge,col[N],c[N],cnt[3];

int mi[3]={0,0,0x3f3f3f3f},up[3]={0,0,0x3f3f3f3f};

void addedge(int u,int v,int w){
	++cntedge;to[cntedge]=v;edge[cntedge]=w;nxt[cntedge]=fir[u];fir[u]=cntedge;
}

namespace subtree{
	queue<int>q;
	void bfs(int u){
		for(int now=fir[u],v;now;now=nxt[now]){
			v=to[now];
			if(col[v]){
				continue;
			}
			c[v]=edge[now]-c[u];
			col[v]=3-col[u];
			++cnt[col[v]];
			ans+=c[v];
			mi[col[v]]=min(mi[col[v]],c[v]);
			up[col[v]]=min(up[col[v]],p[v]-c[v]);
			q.push(v);
		}
	}
	void solve(){
		q.push(1);col[1]=1;++cnt[1];up[1]=p[1];
		while(!q.empty()){
			int u=q.front();q.pop();
			bfs(u);
		}
		if(up[1]+up[2]<0){
			no;
		}
		if(up[1]<0){
			for(int i=1;i<=n;i++){
				col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
			}
			up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
		}
		if(up[2]<0){
			for(int i=1;i<=n;i++){
				col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
			}
			up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
		}
		if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
			no;
		}
		if(mi[1]<0){
			for(int i=1;i<=n;i++){
				col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
			}
			up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
		}
		else if(mi[2]<0){
			for(int i=1;i<=n;i++){
				col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
			}
			up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
		}
		if(cnt[1]==cnt[2]){
			ansa=ansb=ans;
		}
		else if(cnt[1]<cnt[2]){
			ansa=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
			ansb=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
		}
		else{
			ansa=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
			ansb=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
		}
		yes;
	}
}

namespace qwq{
	queue<int>q;
	int s,id=0;bool flag;
	bool check(){
		while(!q.empty()){
			q.pop();
		}
		memset(col,0,sizeof col);
		q.push(s);col[s]=1;ans=c[s];
		while(!q.empty()){
			int u=q.front();q.pop();
			vis[u]=id;
			if(c[u]<0||c[u]>p[u]){
				no;
			}
			for(int now=fir[u],v;now;now=nxt[now]){
				v=to[now];
				if(col[v]){
					if(c[u]+c[v]!=edge[now]){
						no;
					}
					continue;
				}
				c[v]=edge[now]-c[u];
				col[v]=3-col[u];
				ans+=c[v];
				q.push(v);
			}
		}
		ansa+=ans;ansb+=ans;
		return 1;
	}
	void bfs(int u){
		vis[u]=id;
		for(int now=fir[u],v;now;now=nxt[now]){
			v=to[now];
			if(col[v]){
				if(col[u]^col[v]){
					if(c[u]+c[v]!=edge[now]){
						no;
					}
				}
				else{
					if(((c[u]+c[v])&1)^(edge[now]&1)){
						no;
					}
					if(col[u]^2){
						c[s]=(edge[now]-c[u]-c[v])>>1;
						if(check()){
							flag=1;return;
						}
						else{
							no;
						}
					}
					else{
						c[s]=(c[u]+c[v]-edge[now])>>1;
						if(check()){
							flag=1;return;
						}
						else{
							no;
						}
					}
				}
				continue;
			}
			c[v]=edge[now]-c[u];
			col[v]=3-col[u];
			++cnt[col[v]];
			ans+=c[v];
			mi[col[v]]=min(mi[col[v]],c[v]);
			up[col[v]]=min(up[col[v]],p[v]-c[v]);
			q.push(v);
		}
	}
	void work(){
		while(!q.empty()){
			q.pop();
		}
		flag=0;
		memset(cnt,0,sizeof cnt);
		up[2]=mi[2]=0x3f3f3f3f;mi[1]=0;
		q.push(s);col[s]=1;++cnt[1];up[1]=p[s];ans=0;
		while(!q.empty()){
			int u=q.front();q.pop();bfs(u);
		}
		if(flag){
			return;
		}
		if(up[1]+up[2]<0){
			no;
		}
		if(up[1]<0){
			for(int i=1;i<=n;i++){
				if(vis[i]!=id){
					continue;
				}
				col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
			}
			up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
		}
		if(up[2]<0){
			for(int i=1;i<=n;i++){
				if(vis[i]!=id){
					continue;
				}
				col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
			}
			up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
		}
		if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
			no;
		}
		if(mi[1]<0){
			for(int i=1;i<=n;i++){
				if(vis[i]!=id){
					continue;
				}
				col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
			}
			up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
		}
		else if(mi[2]<0){
			for(int i=1;i<=n;i++){
				if(vis[i]!=id){
					continue;
				}
				col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
			}
			up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
		}
		if(cnt[1]==cnt[2]){
			ansa+=ans;ansb+=ans;
		}
		else if(cnt[1]<cnt[2]){
			ansa+=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
			ansb+=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
		}
		else{
			ansa+=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
			ansb+=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
		}
	}
	void solve(){
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				++id;s=i;
				work();
			}
		}
		yes;
	}
}

signed main(){
	qread(n);qread(m);
	for(int i=1;i<=n;i++){
		qread(p[i]);
	}
	for(int i=1,u,v,w;i<=m;i++){
		qread(u);qread(v);qread(w);addedge(u,v,p[u]+p[v]-w);addedge(v,u,p[u]+p[v]-w);
	}
	if(n==m+1){
		subtree::solve();
	}
	else{
		qwq::solve();
	}
	no;
	return 0;
}
posted @ 2019-07-07 16:10  __BLUESKY007  阅读(768)  评论(0编辑  收藏  举报