AcWing 802. 区间和
我超,标记easy的题,我觉得好难!!!不过还是懂了,笑死。
思路:离散化
无限的下标映射到有限的下标捏。
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
type pair struct {
fisrt int
second int
}
var scanner *bufio.Scanner
func readline() []int {
scanner.Scan()
l := strings.Split(scanner.Text(), " ")
res := make([]int, len(l))
for i, s := range l {
x, _ := strconv.Atoi(s)
res[i] = x
}
return res
}
func main() {
scanner = bufio.NewScanner(os.Stdin)
bs := make([]byte, 2000*1024)
scanner.Buffer(bs, len(bs))
var n, m int
fmt.Scanf("%d%d", &n, &m)
add := make([]pair, 0) // 插入操作
query := make([]pair, 0) // 询问操作
alls := make([]int, 0) // alls存储与操作相关的所有坐标(未离散)
for i:=0;i<n;i++{
x := readline()
add = append(add, pair{x[0], x[1]}) // 指定的下标(未离散) + 要加的c
alls = append(alls, x[0]) // x[0]为要纸巾加法的下标(未离散),放进alls
}
for i:=0;i<m;i++{
x := readline()
alls = append(alls, x[0]) // 查询左区间的下标(未离散),加入到alls
alls = append(alls, x[1]) // 查询右区间的下标(未离散),加入到alls
query = append(query, pair{x[0], x[1]})
}
sort.Ints(alls) // 与操作有关的alls数组排序
alls = unique(alls) // alls数组去重
// 处理插入
a := make([]int, len(alls)+1)
for _, item := range add {
x := find(alls, item.fisrt) // 找到add中要记录的所要插入的那个下标,对其离散化
fmt.Println("I am:",x)
a[x] += item.second // 对其离散化的那个下标➕上c
// 此时x是第一个需要插入的那个数 离散化的下标。比如我原来下标是99999,现在离散为下标1
}
// 预处理前缀和
s := make([]int,len(a))
for i:=1;i<=len(alls);i++{
s[i] = s[i-1] + a[i]
}
// 处理询问
for _, item := range query { // 查询左右端点离散化后的下标
l, r := find(alls, item.fisrt), find(alls, item.second)
fmt.Println("I am left and right:",l,r)
// 将其离散后的l和r在s中查询,s是前缀和,记录的是离散后的下标所对应的前缀和。
fmt.Println(s[r]-s[l-1])
}
}
func unique(a []int) (b []int) {
// 已经排过序了
j := 0
for i := 0; i < len(a); i = j {
for j < len(a) && a[j] == a[i] {
j++
}
b = append(b, a[i])
}
return b
}
// 求 x 位置上的值离散化后的结果
func find(alls []int, x int) int {
l, r := 0, len(alls)-1 // 二分查找
for l < r {
mid := l + (r-l)/2
if alls[mid] >= x {
r = mid
} else {
l = mid + 1
}
}
return r + 1 // 把所有数值映射到从1开始的自然数,方便前缀和计算,避免考虑边界
}