1. 程式人生 > 其它 >[ICPC2022濟南站] H.Set of Intervals 【分類討論】

[ICPC2022濟南站] H.Set of Intervals 【分類討論】

分析:

只有一個區間的時候輸出1

只有兩個區間的時候,只有三種情況:包含,相離,相交。可以推出一個數學式子計算相交和相離的情況下的答案,我們用$getans(l_1,r_1,l_2,r_2)$表示。那麼包含的情況的答案則可以通過容斥原理,假設$[l_1,r_1]$是小的區間,則$getans(l_1,r_1,l_2,r_2)+getans(l_2,r_2,l_1,r_1)-getans(l1,r1,l1,r1)$得到。

接下來我們考慮其他情況:

假設現在對於所有區間,其最小的左端點位置為$minl$,由第一個區間提供,最大的右端點位置為$maxr$,也由第一個區間提供,那麼對於剩下的其他$n-1$個區間,可以計算他們的最小值$secl$和他們的最大值$secr$,答案就是上面兩個區間包含的情況的答案。

如果$minl$和$maxr$由不同的區間提供,也就是分別由第一個和第二個區間提供。那麼還是同樣求出其他$n-2$個區間的$secl$和$secr$。

接下來,分幾種情況討論:

1.兩個端點一個在$[minl,maxr]$之中,另一個在$[secl,secr]$之中,這種情況完全可以取到,利用計算包含的函式計算。

2.兩個端點都在$[minl,secl-1]$之中,這個情況可以發現,左端點一定是由第一個區間和其他某個區間的並構成,因此能取到$[minl,secl-1]$的全集。而右端點只能由第二個區間獲得,因為其他區間染指不到$secl-1$以及之前。所以可以利用相交或者包含的那個函式計算

3.兩個端點都在$[secr+1,maxr]$之中,這個情況和情況2對稱

4.左端點在$[minl,sec-1]$,右端點在$[secr+1,maxr]$。這時候,如果有$n\ge 4$,那麼總是可以把第一個區間和其他區間合併,第二個區間和其他區間合併,於是左右端點能取到所有情況,利用相離的計算即可。否則$n=3$,此時可以選擇將左端點和其他區間合併,再將右端點和其他區間合併,分別計算結果,然後再減去算重的部分。

程式碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 105000;
 5 
 6 struct node{
 7     int l,r;
8 }p[maxn]; 9 10 long long calc(int l1,int r1,int l2,int r2){ 11 if(l1 > r1) return 0; 12 if(l2 > r2) return 0; 13 if(r1 < l2){ 14 return 1ll*(r1-l1+1)*(r2-l2+1); 15 }else{ 16 r1 = min(r1,r2); 17 l2 = max(l2,l1); 18 if(l1 > r1) return 0; 19 if(l2 > r2) return 0; 20 return 1ll*(l2-l1)*(r2-l2+1)+1ll*(r1-l2+1)*(r2-l2+r2-r1)/2; 21 } 22 } 23 24 int main(){ 25 ios::sync_with_stdio(false); 26 int t; cin >> t; 27 while(t--){ 28 int n; 29 cin >> n; 30 for(int i=1;i<=n;i++) cin >> p[i].l >> p[i].r; 31 if(n == 1){cout<<1<<endl;continue;} 32 int samepos = 0; 33 int minnl = 1e9,ps1 = 0,maxxr = -1e9,ps2 = 0; 34 for(int i=1;i<=n;i++){ 35 if(p[i].l < minnl && p[i].r > maxxr){ 36 ps1 = i,minnl = p[i].l; 37 ps2 = i,maxxr = p[i].r; 38 }else{ 39 if(p[i].l < minnl){ 40 ps1 = i; 41 minnl = p[i].l; 42 }else if(p[i].r > maxxr){ 43 ps2 = i; 44 maxxr = p[i].r; 45 } 46 } 47 } 48 if(ps1 == ps2){ 49 samepos = 1; 50 swap(p[1],p[ps1]); 51 }else{ 52 if(ps2 == 1 && ps1 == 2){ 53 swap(p[1],p[2]); 54 }else if(ps2 == 1){ 55 swap(p[1],p[2]); 56 swap(p[ps1],p[1]); 57 }else{ 58 swap(p[1],p[ps1]); 59 swap(p[2],p[ps2]); 60 } 61 } 62 if(n == 2 && !samepos){ 63 cout<<calc(p[1].l,p[1].r,p[2].l,p[2].r)<<endl; 64 continue; 65 } 66 int secl = 1e9,secr = -1e9; 67 int st = (samepos == 1?2:3); 68 for(int i=st;i<=n;i++){ 69 secl = min(secl,p[i].l); 70 secr = max(secr,p[i].r); 71 } 72 long long p1 = calc(minnl,maxxr,secl,secr)+calc(secl,secr,minnl,maxxr)-calc(secl,secr,secl,secr); 73 if(samepos == 1){ 74 cout<<p1<<endl; 75 }else{ 76 //both l,secl-1 77 p1 += calc(minnl,secl-1,p[2].l,secl-1); 78 //both r,secr-1 79 p1 += calc(secr+1,p[1].r,secr+1,maxxr); 80 //l,secl-1;r,secr-1; 81 if(n >= 4){ 82 p1 += calc(minnl,secl-1,secr+1,maxxr); 83 }else{ 84 if(p[1].r >= secl-1 || p[2].l <= secr+1){ 85 86 p1 += calc(minnl,secl-1,secr+1,maxxr); 87 }else{ 88 p1 += calc(minnl,secl-1,p[2].l,maxxr)+calc(minnl,p[1].r,secr+1,maxxr)-calc(minnl,p[1].r,p[2].l,maxxr); 89 } 90 } 91 cout<<p1<<endl; 92 } 93 } 94 }