0
点赞
收藏
分享

微信扫一扫

并查集:推导部分和

zhongjh 2023-06-26 阅读 90

推导部分和

问题描述

对于一个长度为 N N N 的整数数列 A 1 , A 2 , ⋯ A N A_{1}, A_{2}, \cdots A_{N} A1,A2,AN, 小蓝想知道下标 l l l r r r 的部 分和 ∑ i = l r = A l + A l + 1 + ⋯ + A r \sum_{i=l}^{r}=A_{l}+A_{l+1}+\cdots+A_{r} i=lr=Al+Al+1++Ar 是多少?

然而, 小蓝并不知道数列中每个数的值是多少, 他只知道它的 M M M 个部分和 的值。其中第 i i i 个部分和是下标 l i l_{i} li r i r_{i} ri 的部分和 ∑ j = l i r i = A l i + A l i + 1 + ⋯ + A r i \sum_{j=l_{i}}^{r_{i}}=A_{l_{i}}+A_{l_{i}+1}+\cdots+A_{r_{i}} j=liri=Ali+Ali+1++Ari, 值是 S i S_{i} Si

输入格式

第一行包含 3 个整数 N 、 M N 、 M NM Q Q Q 。分别代表数组长度、已知的部分和数量 和询问的部分和数量。

接下来 M M M 行, 每行包含 3 个整数 l i , r i , S i l_{i}, r_{i}, S_{i} li,ri,Si

接下来 Q Q Q 行, 每行包含 2 个整数 l l l r r r, 代表一个小蓝想知道的部分和。

输出格式

对于每个询问, 输出一行包含一个整数表示答案。如果答案无法确定, 输出 UNKNOWN。

样例输入

5 3 3
1 5 15
4 5 9
2 3 5
1 5
1 3
1 2

样例输出

15
6
UNKNOWN

评测用例规模与约定

对于 10 10 \\% 10 的评测用例, 1 ≤ N , M , Q ≤ 10 , − 100 ≤ S i ≤ 100 1 \leq N, M, Q \leq 10,-100 \leq S_{i} \leq 100 1N,M,Q10,100Si100

对于 20 20 \\% 20 的评测用例, 1 ≤ N , M , Q ≤ 20 , − 1000 ≤ S i ≤ 1000 1 \leq N, M, Q \leq 20,-1000 \leq S_{i} \leq 1000 1N,M,Q20,1000Si1000

对于 30 30 \\% 30 的评测用例, 1 ≤ N , M , Q ≤ 50 , − 10000 ≤ S i ≤ 10000 1 \leq N, M, Q \leq 50,-10000 \leq S_{i} \leq 10000 1N,M,Q50,10000Si10000

对于 40 40 \\% 40 的评测用例, 1 ≤ N , M , Q ≤ 1000 , − 1 0 6 ≤ S i ≤ 1 0 6 1 \leq N, M, Q \leq 1000,-10^{6} \leq S_{i} \leq 10^{6} 1N,M,Q1000,106Si106

对于 60 60 \\% 60 的评测用例, 1 ≤ N , M , Q ≤ 10000 , − 1 0 9 ≤ S i ≤ 1 0 9 1 \leq N, M, Q \leq 10000,-10^{9} \leq S_{i} \leq 10^{9} 1N,M,Q10000,109Si109

对于所有评测用例, 1 ≤ N , M , Q ≤ 1 0 5 , − 1 0 12 ≤ S i ≤ 1 0 12 , 1 ≤ l i ≤ r i ≤ N 1 \leq N, M, Q \leq 10^{5},-10^{12} \leq S_{i} \leq 10^{12}, 1 \leq l_{i} \leq r_{i} \leq N 1N,M,Q105,1012Si1012,1liriN, 1 ≤ l ≤ r ≤ N 1 \leq l \leq r \leq N 1lrN 。数据保证没有矛盾。

解题思路一 加权并查集

灵光一闪:部分和+重复
(多次求部分和最快方法——前缀和)
给出指定区间 [ l , r ] [l,r] [l,r] 的部分和,根据前缀和的思想,若下标 l , r l,r l,r 处的前缀和分别为 S l , S r S_{l},S_{r} Sl,Sr ,那么区间 [ l , r ] [l,r] [l,r] 的部分和可表示为 S r − S l − 1 S_{r}-S_{l-1} SrSl1.
问题
不知道数组全貌,没办法求完整的前缀和
基本情况
给出指定区间 [ l , r ] [l,r] [l,r] 的部分和,问我们区间 [ l , r ] [l,r] [l,r]的部分和
简单延申
给出指定区间 [ l , r ] [l,r] [l,r] [ r , r + k ] [r,r+k] [r,r+k]的部分和,问我们区间 [ l , r + k ] [l,r+k] [l,r+k]的部分和
发现
l指向r,r指向r+k,结果两两组合都可以求出来部分和——并查集

注意:由于部分和的值始终为编号较小的结点 d i s [ l ] dis[l] dis[l] 与编号较大的结点 d i s [ r ] dis[r] dis[r] 间的差值,因此对于一个结点 i i i ,若其并查集祖宗结点 j j j 的编号大于 i i i ,那么 d i s [ i ] dis[i] dis[i] 记录的距离为 s s s ,否则,记录的是 s s s 的负数。例如,结点 4 到 5 的距离为 6 ,那么结点 5 到结点 4 的距离为 -6 。
步骤
1、初始化:需要将并查集数组有效部分的长度初始化为 n + 1 n+1 n+1 ,
2、合并:对于每个输入的区间端点 l , r l,r l,r 和部分和 s s s ,并查集结点 l − 1 l-1 l1 r r r 之间的距离为 s s s, 结点合并时,并查集的权数组 d i s dis dis 维护 s s s.
3、将所有的区间和进行并查集连通后,对输入的需要求解的区间和 [ q l , q r ] [ql,qr] [ql,qr] 进行判断,如果 q l , q r ql,qr ql,qr 有相同的祖宗结点,那么 d i s [ q l ] − d i s [ q r ] dis[ql]-dis[qr] dis[ql]dis[qr] 即为区间和。否则,说明 q l , q r ql,qr ql,qr 并不连通,此时无法求出区间和。

AC Code(Python3)

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
N=int(1e5)+10

father=[0]*N
dis=[0]*N
def init(n:int):
    for i in range(1,n+1):
        father[i]=i
def find_father(x:int):
    if father[x]==x:return x
    t=father[x]   
    father[x]=find_father(father[x])
    dis[x]+=dis[t]                      #权重数组dis维护两个结点间的距离,此题为区间和
    return father[x]
def unite(x:int,y:int,w:int):
    fx=find_father(x); fy=find_father(y)
    if fx==fy:return
    father[fx]=fy
    dis[fx]=dis[y]-dis[x]+w         #合并时维护节点间的区间和(fx>fy则为负值,fx<fy则为正值)

if __name__=='__main__':
    n,m,q=map(int,input().split())
    init(n)                         #对加权并查集初始化
    for i in range(m):
        l,r,s=map(int,input().split())
        l-=1                        #类似前缀和,[l,r]的和为l-1到r的距离
        unite(l,r,s)                #合并结点l与r
    res=[]                          #存放结果的列表
    for i in range(q):
        ql,qr=map(int,input().split())
        ql-=1                       #与l情况相同
        faql=find_father(ql); faqr=find_father(qr)
        if(faql!=faqr):res.append("UNKNOWN")    #两个结点不连通,此时的和不可求解
        else:res.append(dis[ql]-dis[qr])  #部分和为两结点间dis的差值(由前缀和性质,部分和一定是左边区间减右边区间)
    for item in res:
        print(item)
举报

相关推荐

部分和(dfs)

算法基础进阶部分-并查集

堆和并查集

[并查集][C++]并查集模板

并查集__

并查集

java并查集

0 条评论