目录
- 1.推导部分和
- 1.题目描述
- 2.输入格式
- 3.输入格式
- 4.样例输入
- 5.样例输出
- 6.数据范围
- 7.原题链接
- 2.解题思路
- 3.Ac_code
1.推导部分和
1.题目描述
对于一个长度为 的整数数列
, 小蓝想知道下标
到
的部分和
是多少?
然而, 小蓝并不知道数列中每个数的值是多少, 他只知道它的 个部分和 的值。
其中第 个部分和是下标
到
的部分和
, 值是
。
2.输入格式
第一行包含 3 个整数 和
接下来 行, 每行包含 3 个整数
。接下来
行, 每行包含 2 个整数
和
, 代表一个小蓝想知道的部分和。
3.输入格式
对于每个询问, 输出一行包含一个整数表示答案。如果答案无法确定, 输出 UNKNOWN。
4.样例输入
5 3 3
1 5 15
4 5 9
2 3 5
1 5
1 3
1 2
5.样例输出
15
6
UNKNOWN
6.数据范围
对于所有评测用例,
2.解题思路
的和,我们一般是写为
。如果已知区间
的和,这意味着我们可以从
跳转到
。
如图,假设给定区间和
的和,很明显两个区间结合起来我们可以得到
的和。我们一段已知区间
,我们将
和
连通起来,如图红线。可知
处于一个连通分量,这意味着我们可以通过
来得到区间
的和以及
来得到
的和,最主要的是可以通过
来得到
的和,由此可以产生合并效果。
的值时,我们只需要判断
和
是否属于同一个连通分量即可,如果不是则说明无解输出UNKNOWN。当然题目需要我们输出具体的区间和而不是判断是否能求解出,所以朴素的并查集并无法满足我们的要求,我们需要使用带权并查集。
不熟悉带权并查集的同学请回顾前文:带权并查集
我们同样来维护到头结点的距离,而头结点应当是每个联通分量最右端的点,如果上图点 4
到 点 7
的距离就是 区间和,而点
1
到 点 4
的距离同理可维护。因为 7
才应该是头结点,所以 1
到 7
的距离应当是 1
到 4
加上 4
到 7
,这在并查集路径压缩中可实现。求解区间 时,只需要用
即可,
d[]
则是维护联通分量中到头结点的距离,具体细节见代码。
3.Ac_code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) (int)s.size();
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;
struct UF {
std::vector<LL> f, d;
UF(int n) : f(n), d(n, 0) { std::iota(f.begin(), f.end(), 0); }
int find(int x) {
if (x == f[x]) return x;
//先记录祖宗
int root = find(f[x]);
//加上父亲的距离
d[x] += d[f[x]];
return f[x] = root;
}
bool same(int x, int y) { return find(x) == find(y); }
bool merge(int u, int v, LL w) {
int x = find(u);
int y = find(v);
if (x == y) return false;
f[x] = y;
d[x] = w + d[v] - d[u];
return true;
}
};
int n, m, q;
LL s;
void solve()
{
cin >> n >> m >> q;
UF uf(n + 10);
for (int i = 1; i <= m; ++i)
{
LL l, r , s;
cin >> l >> r >> s;
uf.merge(l - 1, r , s);
}
for (int i = 1; i <= q; ++i)
{
int l, r;
cin>>l>>r;
if (!uf.same(l - 1, r)) cout << "UNKNOWN" << '\n';
else cout << uf.d[l - 1] - uf.d[r] << '\n';
}
}
int main()
{
ios_base :: sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while (t--)
{
solve();
}
return 0;
}