[蓝桥杯 2022 省 A] 推导部分和——图论建模
题意简述
给定一个序列以及这个序列几个部分的数字之和,求询问的部分数字之和。
当无法确定时报告无解。
思路
看了题之后感觉不是可以直接上手的那种。想到了将部分和用前缀和的形式转化:设 \(s_x = \sum\limits_{i=1}^{x}A_i\),则 \(\sum\limits_{i=l}^{r}A_i=s_r-s_{l-1}\)。
也就是说,题目给出的 \(l_i,r_i,S_i\) 也就是 \(s_{r_i}-s_{l_i-1}=S_i\)。于是想到了图论建模,即在 \(l-1,r\) 之间连边,其中 \(l-1 \rightarrow r\) 的长度为 \(S_i\),\(r \rightarrow l-1\) 的长度为 \(-S_i\)。这样建图,我们就形成了一个由多个连通块组成的图。
对于每一次询问 \(l,r\),我们也就是输出 \(s_r-s_{l-1}\) 即可……吗?
我么发现,如果 \(l-1,r\) 无法通过已知的条件联系起来就没有办法求值。而如果能够联系起来,则 \(l-1,r\) 在同一个连通块内。于是自然想到用并查集来维护哪些点处于同一个连通块内。
每一个联通块都有一个 \(s_i=0\),这显然不影响,因为实际上,最后我考虑的是这几个点的相对距离,与他的数值没有实质关系。
于是对每一个联通块 bfs 就把这个题做完了。
代码
#include <bits/stdc++.h>
#define loop(i,a,b) for(int i=(a);i<=(int)(b);i++)
using namespace std;
typedef long long ll;
const int N=1e5+5;
const ll inf=1e18;
int n,m,q,fa[N];
int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void connect(int u,int v){
int fu=find(u),fv=find(v);
fa[fu]=fv;
return;
}
struct side{
int to;
ll w;
};
vector<side>g[N];
ll sum[N];
bool vis[N];
void bfs(int st){
queue<int>q;
q.push(st);
while(!q.empty()){
int u=q.front();
q.pop();
for(auto s:g[u]){
int v=s.to;
connect(u,v);
sum[v]=sum[u]+s.w;
if(!vis[v])q.push(v),vis[v]=1;
}
}
return;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>q;
int l,r;
ll S;
loop(i,1,m){
cin>>l>>r>>S;
g[l-1].push_back({r,S});
g[r].push_back({l-1,-S});
}
loop(i,0,n)fa[i]=i;
loop(i,0,n)if(fa[i]==i)bfs(i);
while(q--){
cin>>l>>r;
if(find(l-1)==find(r))cout<<sum[r]-sum[l-1]<<'\n';
else cout<<"UNKNOWN\n";
}
return 0;
}
完结撒花花~
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/20080043

浙公网安备 33010602011771号