152周 區間求差

2021-08-01 22:38:14 字數 1695 閱讀 9638

這道題是一類區間問題的變體,我們先來看一道最基礎的區間問題:

給定n個區間[s1, e1], [s2, e2], ... [sn, en],求這些區間並集的長度。

這道題通常的解法是,我們把這n個區間的2n個端點從左到右排列在數軸上p1, p2, ... p2n。並且如果乙個點pi是原區間的左端點,我們就把它標記成綠色;如果是右端點,就標記成藍色。

值得注意的是這2n個點中可能存在重合的點。比如假設有兩個區間[1, 3]和[3, 5],那麼在3這個位置上就同時存在乙個綠點(左端點)和藍點(右端點)。某些情況下我們在排序時需要特別處理重合的點,例如要保證藍點都排在綠點之前。不過本題我們無需特殊處理,重合的點無論誰在前誰在後都不影響結果。

這2n個點把數軸分成了2n+1段,(-inf, p1), (p1, p2), (p2, p3) ... (p2n-1, p2n), (p2n, +inf)。每一段內部被原來區間集合覆蓋的情況都是相同的。換句話說,不會出現(pi, pi+1)的左半部分被第1、3、5號區間覆蓋,而右半部分只被第1、3號區間覆蓋這種情況。

所以我們可以從左到右掃瞄每一段,令cnt計數器初始值=0。當掃過乙個綠點時,cnt++;掃過乙個藍點時cnt--。我們可以發點對於(pi, pi+1)這一段,處理完pi時的cnt值恰好代表了這一段被幾個原來的區間同時覆蓋。

有了每一段的cnt值,我們可以做很多事情。例如要求區間並集的長度,我們可以找出所有cnt值大於0的段(pi, pi+1),並把這些段的長度(pi+1 - pi)求和。

我們還可以知道哪段被覆蓋了最多次:自然是cnt值最大的段。

對於給定的座標x,我們可以在o(logn)的時間內求出x這個點被覆蓋多少次:我們只需要在p1, p2, ... p2n中二分查詢出x的位置,即pi < x < pi+1,那麼(pi, pi+1)這一段的cnt值就是答案。(當x恰好是端點時需要特判,取決於給出的區間是開區間還是閉區間)

好了,我們回到《區間求差》這道題目。我們可以把a和b集合中2n+2m個端點都從左到右排列在數軸上。並且用4種顏色標記出每個點是a的左端點、a的右端點、b的左端點、b的右端點。

然後我們用兩個計數器cnta和cntb來分別維護每一段被a集合中的區間覆蓋多少次、以及被b集合的區間覆蓋多少次。那麼如果某一段(pi, pi+1)滿足cnta>0且cntb=0,那麼它一定是a-b的一部分。我們對於這些段的長度求和即可。

整個演算法對於端點排序的部分複雜度是o(nlogn)的,對於從左到右掃瞄複雜度是o(n)的。總體複雜度是o(nlogn)。

以上直接copy hihocoder 討論區

# include # include # include using namespace std;

# define mem(x,y) memset(x,sizeof(x),y);

const int maxn = 1e5+100;

struct node

}if(a[i].type==1) cnt1++;

if(a[i].type==2) cnt1--;

if(a[i].type==3) cnt2++;

if(a[i].type==4) cnt2--;

last=a[i].x;

} printf("%lld\n",ans);

} return 0;

}

區間問題 hiho一下第152周 區間求差

hiho一下第152周 區間求差 時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 給定兩個區間集合 a 和 b,其中集合 a 包含 n 個區間 a1 a2 a3 a4 a2n 1 a2n 集合 b 包含 m 個區間 b1 b2 b3 b4 b2m 1 b2m 求 a b 的...

hiho 1305 區間求差

時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 給定兩個區間集合 a 和 b,其中集合 a 包含 n 個區間 a1,a2 a3,a4 a2n 1,a2n 集合 b 包含 m 個區間 b1,b2 b3,b4 b2m 1,b2m 求 a b 的長度。例如對於 a b a b 長...

hihocoder 1305 區間求差

you are given two interval collections a and b.collection a has n intervals a1 a2 a3 a4 a2n 1 a2n and collection b has m intervals b1 b2 b3 b4 b2m 1 b...