题意:
题目描述
(X) 国有 (N) 座城市,由 (N-1) 条道路连接形成了一棵树,每条边都有边权 (wi) 表示经过这条边需要 (wi) 的时间。为了方便出行,(X) 国计划在每座城市建造一座传送装置,它们两两之间可以进行传送。传送并不是即时的,初始时你需要给每个传送装置设置一个参数 (ai),从装置 (i) 传送到装置 (j) 需要花费 (|ai-aj|) 的时间。
(X) 国并不希望得不偿失的情况发生,因此不能有任意两个城市之间通过传送需要的时间超过走路时间。同时,由于传送装置受每个城市的地质情况限制,每个城市的传送装置参数 (ai) 只能是区间 ([li, ri]) 之内。当然你也可以对城市的地质进行改造,花费 (x)的代价可以使所有城市能接受的参数区间扩大为 ([li- x, ri + x])。代价必须是一个非负整数。
问在不进行改造的情况下,能否找到一种安排 (ai) 的方案,满足上述所有要求。有时你还需要回答在允许进行改造的情况下,最少花费多少代价进行改造,可以找到一种方案满足要求 (如果不需要改造就可满足则输出 (0))。
输入格式
第一行两个整数 (T,typ),表示数据组数和数据类型。
对于每组数据,第一行一个整数 N 表示城市的数量。
接下来一行 (N) 个整数,第 (i) 个表示 (li)。
接下来一行 (N) 个整数,第 (i) 个表示 (ri)。
接下来 (N-1) 行,每行三个整数 (u,v,w),表示一条道路连接 (u) 和 (v),权值为(w)。
输出格式
对于每组数据,如果 (typ = 0),则输出一行一个 0(可以满足要求) 或 1(不满足要求)。
如果 (typ = 1),则输出一行一个整数表示需要的最小代价。
样例输入
1 1
4
1 3 5 7
2 4 6 8
1 2 1
4
1 3 2
1 4 1
样例输出
2
数据范围与约定
对于 (20)% 的数据,(1 ≤ N ≤ 5,w, |li|, |ri| ≤ 8;)
对于 (40)% 的数据,(1 ≤ N ≤ 70);
对于 (65)% 的数据,(1 ≤ N ≤ 1000);
对于额外 (15)% 的数据, 保证 (w = 0);
对于 (100)% 的数据,保证 (1 ≤ T ≤ 3),(typ ∈ {0or1},1 ≤ N ≤ 10^6,0 ≤ w, |li|, |ri| ≤ 109)。
在所有测试点内,均匀分布着约 (20)% 的数据,保证 (typ = 0)。
思路:
首先发现这道题条件稍显繁琐,考虑将它进行简化
仔细读题,一种差分约束的感觉扑面而来
于是在原树的基础上新设一个点T,
向每个节点连边权为ri的单向边,由每个节点向T连边权为-li的单向边
于是发现是否有解取决于是否存在负环。
typ=0情况解决
typ=1时,不难发现其单调性,二分答案判断即可
至于如何判断负环,可用树形DP或spfa
启发:
差分约束加的边可以与原图结合在一起
p.s. 此题好像可以不用二分,可惜我太菜了。。。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int tot,t,n,top;
int l[N],r[N];
int fi[N],ne[N<<1],to[N<<1],w[N<<1];
int sta[N];
long long d[N];
bool type,insta[N];
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
inline void add(int x,int y,int s)
{
ne[++tot]=fi[x],fi[x]=tot,to[tot]=y,w[tot]=s;
}
bool dfs_spfa(int u,int pos)
{
sta[++top]=u;insta[u]=true;
for(int i=fi[u];i;i=ne[i])
{
int v=to[i];
if(d[u]+1ll*w[i]<d[v])
{
if(insta[v])return true;
d[v]=d[u]+1ll*w[i];
if(dfs_spfa(v,pos))return true;
}
}
--top;insta[u]=false;
return false;
}
inline bool go(int u,int pos)
{
for(int i=1;i<=n;++i)
d[i]=1e15,insta[i]=false;
d[n+1]=0;
top=0;
return dfs_spfa(u,pos);
}
inline bool ck(int pos)
{
for(int i=1;i<=n;++i)w[i+2*n-2]+=pos;
for(int i=1;i<=n;++i)w[i+3*n-2]+=pos;
bool ff=go(n+1,pos);
for(int i=1;i<=n;++i)w[i+2*n-2]-=pos;
for(int i=1;i<=n;++i)w[i+3*n-2]-=pos;
return !ff;
}
inline void clear()
{
tot=0;
for(int i=1;i<=n+1;++i)fi[i]=0;
}
int main()
{
// freopen("teleport.in","r",stdin);
// freopen("teleport.out","w",stdout);
t=read(),type=read();
while(t--)
{
n=read();
bool flag=0;
for(int i=1;i<=n;++i)l[i]=read();
for(int i=1;i<=n;++i)r[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),_w=read();
add(u,v,_w),add(v,u,_w);
if(_w) flag=1;
}
int mx=-1e9;
for(int i=1;i<=n;++i)mx=max(mx,l[i]);
int mn=1e9;
for(int i=1;i<=n;++i)mn=min(mn,r[i]);
if(mx<=mn){puts("0");clear();continue;}
int ans=mx-mn;
if(!flag)
{
if(!type) puts("1");
else printf("%d
",(ans&1)?(ans/2+1):(ans>>1));
clear();continue;
}
for(int i=1;i<=n;++i)add(i,n+1,-l[i]);
for(int i=1;i<=n;++i)add(n+1,i,r[i]);
if(!type)
{
if(go(n+1,0)) puts("1");
else puts("0");
clear();
continue;
}
int ll=0,rr=ans;
while(ll<rr)
{
int mid=ll+rr>>1;
if(ck(mid)) rr=mid;
else ll=mid+1;
}
printf("%d
",rr);
clear();
}
return 0;
}
考场代码+改动,有些繁琐