[蓝桥杯 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;
}

完结撒花花~

posted @ 2026-05-19 14:06  Circle_Table  阅读(2)  评论(0)    收藏  举报