LC1782 统计点对的数目

发布时间 2023-08-24 16:20:53作者: yxu0528

隐藏在图论里的双指针问题。

一个很容易想到的思路是,枚举每一条边,算出各个点的入度 \(deg_i\),同时用哈希表统计重边数量;然后,对于每个询问,枚举点对,求出 \(deg_x+deg_y-重边数量\)。这样做的复杂度是 \(O(m+qn^2)\),怎么优化?

关注这个复杂度中的 \(n^2\),它所做的事情可以抽象为:统计在 \(deg\) 数组中,有多少个数对的和大于 \(queries_i\)——不难发现,这可以通过排序+双指针解决。从大到小排序 \(deg\),如果当前 \(deg_{left}+deg_{right}>queries_i\) 成立,那么左指针处在当前左指针(含)到右指针之间的所有位置时,这一条件都成立,答案增加 \(right-left\),右指针左移 \(1\);否则左指针右移 \(1\)

去重方式也要随之改变:在完成双指针枚举后,我们枚举每一条边进行检查,如果 \(deg_x+deg_y>queries_i\),但是 \(deg_x+deg_y-重边数量<queries_i\),则答案减 \(1\)

最终的时间复杂度是 \(O(m+q(n\log n+n+m))\)

下面是 AC 代码:

func countPairs(n int, edges [][]int, queries []int) []int {
    deg := make([]int, n+1)
    type edge struct{ x, y int }
    cntE := map[edge]int{}
    for _, e := range edges {
        x := e[0]
        y := e[1]
        if x > y {
            x, y = y, x
        }
        deg[x]++
        deg[y]++
        cntE[(edge{x, y})]++
    }
    answer := make([]int, len(queries))
    sortedDeg := append([]int(nil), deg...)
    sort.Ints(sortedDeg)
    for i, q := range queries {
        left, right := 1, n
        for left < right {
            if sortedDeg[left]+sortedDeg[right] <= q {
                left++
            } else {
                answer[i] += right - left
                right--
            }
        }
        for e, c := range cntE {
            s := deg[e.x] + deg[e.y]
            if s > q && s-c <= q {
                answer[i]--
            }
        }
    }
	return answer
}

THE END