2021.07.06【NOIP提高B组】模拟 总结
第一题:发现答案是一段区间,每次暴力加边,用并查集判断一下。
第二题:显然是动态规划,然后单调队列或线段树优化。
第三题:考虑把组合起来的数算出来,如果这个数为000,计算一下最小代价ccc,就是一个最小生成树。接着我们设fif_ifi表示选了状态为iii的答案。转移就是fi∣j=fi+cjf_{i|j}=f_{i}+c_jfi∣j=fi+cj。
第四题:考虑把车站算成一个点n+1n+1n+1,然后能走的边一定是在这个图的最大生成树上。贪心选择做这个题,不要管买不能丢钱的限制,每次选完所有的钱,然后贪心做一下,看一看树上的两点上最小的权值是多少,去一下min\minmin。
#include<bits/stdc++.h>
using namespace std;
long long n,m,q,ord[100005],lim[100005];
struct edge{
long long x,y,z;
}e[200005];
long long fa[100005],tra[100005];
bool cmp(edge e1,edge e2){
return e1.z>e2.z;
}
const long long inf=1000000000000000000;
long long cnt=0,la[100005],to[400005],we[400005],ne[400005],f[100005][17],g[100005][17],dep[100005];
void add(long long x,long long y,long long z){
++cnt;
to[cnt]=y;
we[cnt]=z;
ne[cnt]=la[x];
la[x]=cnt;
}
long long find(long long x){
if (x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
void dfs(long long x,long long y,long long w){
f[x][0]=y;
g[x][0]=w;
for (long long i=1;i<=16;i++){
f[x][i]=f[f[x][i-1]][i-1];
g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
}
dep[x]=dep[y]+1;
for (long long i=la[x];i;i=ne[i]){
long long z=to[i];
if (z!=y)
dfs(z,x,we[i]);
}
}
void query(long long &ans1,long long &ans2,long long x,long long y){
if (x==y){
ans1=inf;
ans2=0;
return;
}
if (dep[x]<dep[y]) swap(x,y);
ans1=ans2=inf;
long long k=dep[x]-dep[y],s=0;
while (k){
if (k&1) ans1=min(ans1,g[x][s]),x=f[x][s];
s++;
k>>=1;
}
if (x==y){
ans2=x;
return;
}
for (long long i=16;i>=0;i--){
if (f[x][i]!=f[y][i]){
ans1=min(ans1,min(g[x][i],g[y][i]));
x=f[x][i];
y=f[y][i];
}
}
ans1=min(ans1,min(g[x][0],g[y][0]));
ans2=f[x][0];
return;
}
int main(){
freopen("motorcycle.in","r",stdin);
freopen("motorcycle.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&q);
for (long long i=1;i<=n;i++) scanf("%lld",&ord[i]);
for (long long i=1;i<=n;i++) scanf("%lld",&lim[i]);
for (long long i=1;i<=m;i++) scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z);
while (q--){
long long x;
scanf("%lld",&x);
tra[x]=1;
}
for (long long i=1;i<=m;i++){
if (tra[e[i].x]) e[i].x=n+1;
if (tra[e[i].y]) e[i].y=n+1;
if (e[i].x==e[i].y) e[i].z=0;
}
sort(e+1,e+m+1,cmp);
int tot=0;
for (long long i=1;i<=n+1;i++) fa[i]=i;
for (long long i=1;i<=m;i++){
long long x=find(e[i].x);
long long y=find(e[i].y);
if (x==y) continue;
else{
add(e[i].x,e[i].y,e[i].z);
add(e[i].y,e[i].x,e[i].z);
fa[x]=y;
}
}
long long root=0;
for (long long i=1;i<=n+1;i++)
if (la[i])
root=i;
dfs(root,0,inf);
long long now=ord[1],nsum=lim[ord[1]];
if (nsum<=0){
printf("%lld\n",0);
nsum=max(nsum,(long long)0);
}
for (long long i=2;i<=n;i++){
long long x=(tra[ord[i-1]]?(n+1):ord[i-1]);
long long y=(tra[ord[i]]?(n+1):ord[i]);
long long lca,dis;
query(dis,lca,x,y);
nsum=min(nsum,dis);
if (lim[ord[i]]<0){
printf("%lld\n",min(nsum,-lim[ord[i]]));
}
nsum+=lim[ord[i]];
nsum=max(nsum,(long long)0);
}
}