【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;
}