1. 程式人生 > 實用技巧 >【YbtOJ#20073】鑽石守衛

【YbtOJ#20073】鑽石守衛

題目

題目連結:http://noip.ybtoj.com.cn/problem/20073

思路

發現一個連通塊內,我們只要確定了一個點的權值,其他點的權值都可以求出。
所以我們可以設其中一個點權值為 \(x\),然後根據每條道路連線兩個點的點權和等於路徑權值可以將每一個點的權值寫成若干個 \(kx+b\) 的形式。
對於第 \(i\) 個點的所有方程,都需要滿足 \(0\leq kx+b\leq p_i\),所以我們可以解出 \(x\) 的取值範圍。
然後對於同一個點,關於它的所有方程的值都必須一致。所以如果存在兩個方程無解,那麼整張圖無解;如果兩個方程有唯一解,那麼第一個點的權值也只有唯一解,其他點同理也都只有唯一解;否則肯定是在 \(x\)

取值範圍區間的最小值和最大值取答案最優。
所以將每一個方程求出並計算答案即可。
時間複雜度 \(O(n+m)\)

程式碼

本程式碼由於常數過大隻可以得到 \(80\) pts。實在是卡不動了 /kk。

//#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;

const int N=500010,M=6000010;
int n,m,tot,L,R,p[N],head[N],vis[N],a[N],K[N],B[N];
ll mxans,mnans,QuantAsk,my_dog;
bool flag=1;
vector<pair<int,int> > equ[N];

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

struct edge
{
	int next,to,dis;
}e[M];

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

void bfs1(int S)
{
	queue<int> q;
	q.push(S);
	while (q.size())
	{
		int x=q.front(); q.pop();
		a[++tot]=x;
		vis[x]=1; 
		int k=equ[x][0].ST,b=equ[x][0].ND;
		for (int i=head[x];~i;i=e[i].next)
		{
			int v=e[i].to;
		/*	if (v!=fa)
			{*/
				//equ[v].push_back(mp(-k,e[i].dis-b));
				
				int k1=equ[x][i].ST,k2=equ[x][i-1].ST;
				int b1=equ[x][i].ND,b2=equ[x][i-1].ND;
				if (k1==k2 && b1==b2) continue;
				if (k1==k2 && b1!=b2) { flag=0; return; }
		//		if (k1!=k2 && b1==b2) { flag=0; return; }
				if ((b2-b1)%(k1-k2)) { flag=0; return; }
				if ((b2-b1)/(k1-k2)<L || (b2-b1)/(k1-k2)>R) { flag=0; return; }
				L=R=(b2-b1)/(k1-k2);
				
				if (!vis[v]) q.push(v),vis[v]=1;
			//}
		}
		for (int i=0;i<equ[x].size();i++)
			if (equ[x][i].ST==1)
				L=max(L,-equ[x][i].ND),R=min(R,p[x]-equ[x][i].ND);
			else
				L=max(L,equ[x][i].ND-p[x]),R=min(R,equ[x][i].ND);
	}
}
/*
void dfs1(int x,int fa)
{
	vis[x]=1; 
	int k=equ[x][0].ST,b=equ[x][0].ND;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa)
		{
			equ[v].push_back(mp(-k,e[i].dis-b));
			if (!vis[v]) dfs1(v,x);
		}
	}
	for (int i=0;i<equ[x].size();i++)
		if (equ[x][i].ST==1)
			L=max(L,-equ[x][i].ND),R=min(R,p[x]-equ[x][i].ND);
		else
			L=max(L,equ[x][i].ND-p[x]),R=min(R,equ[x][i].ND);
}
*/
void bfs2(int S)
{
	queue<int> q;
	q.push(S);
	while (q.size())
	{
		int x=q.front(); q.pop();
		vis[x]=2;
		for (int i=1;i<equ[x].size();i++)
		{
			int k1=equ[x][i].ST,k2=equ[x][i-1].ST;
			int b1=equ[x][i].ND,b2=equ[x][i-1].ND;
			if (k1==k2 && b1==b2) continue;
			if (k1==k2 && b1!=b2) { flag=0; return; }
	//		if (k1!=k2 && b1==b2) { flag=0; return; }
			if ((b2-b1)%(k1-k2)) { flag=0; return; }
			if ((b2-b1)/(k1-k2)<L || (b2-b1)/(k1-k2)>R) { flag=0; return; }
			L=R=(b2-b1)/(k1-k2);
		}
		for (int i=head[x];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (vis[v]!=2) q.push(v),vis[v]=2;
			if (!flag) return;
		}
	}
}
/*
void dfs2(int x)
{
	vis[x]=2;
	for (int i=1;i<equ[x].size();i++)
	{
		int k1=equ[x][i].ST,k2=equ[x][i-1].ST;
		int b1=equ[x][i].ND,b2=equ[x][i-1].ND;
		if (k1==k2 && b1==b2) continue;
		if (k1==k2 && b1!=b2) { flag=0; return; }
//		if (k1!=k2 && b1==b2) { flag=0; return; }
		if ((b2-b1)%(k1-k2)) { flag=0; return; }
		if ((b2-b1)/(k1-k2)<L || (b2-b1)/(k1-k2)>R) { flag=0; return; }
		L=R=(b2-b1)/(k1-k2);
	}
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (vis[v]!=2) dfs2(v);
		if (!flag) return;
	}
}
*/

void bfs3(int S)
{
	queue<int> q;
	q.push(S);
	while (q.size())
	{
		int x=q.front(); q.pop();
		vis[x]=3;
		int k=equ[x][0].ST,b=equ[x][0].ND;
		QuantAsk+=p[x]-(k*L+b); my_dog+=p[x]-(k*R+b);
		for (int i=head[x];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (vis[v]!=3) q.push(v),vis[v]=3;
		}
	}
}
/*
void dfs3(int x)
{
	vis[x]=3;
	int k=equ[x][0].ST,b=equ[x][0].ND;
	QuantAsk+=p[x]-(k*L+b); my_dog+=p[x]-(k*R+b);
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (vis[v]!=3) dfs3(v);
	}
}*/

int main()
{
	freopen("diamond.in","r",stdin);
	freopen("diamond.out","w",stdout);
	memset(head,-1,sizeof(head));
	n=read(); m=read();
	for (int i=1;i<=n;i++)
		p[i]=read();
	for (int i=1,x,y,z;i<=m;i++)
	{
		x=read(); y=read(); z=read();
		add(x,y,z); add(y,x,z);
	}
	for (int i=1;i<=n;i++)
		if (!vis[i])
		{
			L=0; R=1e9; QuantAsk=my_dog=0; tot=0;
			equ[i].push_back(mp(1,0));
			//dfs1(i,0); dfs2(i);
			bfs1(i); /*bfs2(i);*/
			for (int k=1;k<=tot;k++)
			{
				int x=a[k];
				for (int j=1;j<equ[x].size();j++)
				{
					int k1=equ[x][j].ST,k2=equ[x][j-1].ST;
					int b1=equ[x][j].ND,b2=equ[x][j-1].ND;
					if (k1==k2 && b1==b2) continue;
					if (k1==k2 && b1!=b2) { flag=0; break; }
			//		if (k1!=k2 && b1==b2) { flag=0; break; }
					if ((b2-b1)%(k1-k2)) { flag=0; break; }
					if ((b2-b1)/(k1-k2)<L || (b2-b1)/(k1-k2)>R) { flag=0; break; }
					L=R=(b2-b1)/(k1-k2);
				}
			}
			if (!flag || L>R) return printf("NIE"),0;
			//dfs3(i);
			for (int j=1;j<=tot;j++)
			{
				int k=equ[a[j]][0].ST,b=equ[a[j]][0].ND;
				QuantAsk+=p[a[j]]-(k*L+b); my_dog+=p[a[j]]-(k*R+b);
			}
			//bfs3(i);
			mnans+=min(my_dog,QuantAsk);
			mxans+=max(my_dog,QuantAsk);
		}
	printf("%lld %lld",mnans,mxans);
	return 0;
}