Codeforces1462F The Treasure of The Segments
阿新 • • 發佈:2020-12-20
Solution
列舉哪個線段與其他所有線段重合,並通過樹狀陣列計算與之重合的線段的數量,數量最多的即為所求線段。
至於如何統計,可以將所有線段以左端點為第一關鍵字、右端點為第二關鍵字排序,對於每一個線段 \([l_i,r_i]\),左端點小於它的(\([l_1,r_1],[l_2,r_2],\cdots,[l_{i-1},r_{i-1}]\)),統計右端點處於區間 \([l_i,r_i]\) 的有多少個;左端點大於它的(\([l_{i+1},r_{i+1}],[l_{i+2},r_{i+2}],\cdots,[l_n,r_n]\)),統計左端點處於區間 \([l_i,r_i]\),二者相加的和即與該線段重合的線段的數量。由於 \(1 \leq l \leq r \leq 10^9\)
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; const int N=2e5; struct segment { int l,r; segment() {} bool operator < (const segment &x) const {return l==x.l?r<x.r:l<x.l;} }a[N+10]; int c1[N*2+10],c2[N*2+10],n,m,t[N*2+10]; void modify(int *c,int x,int d) {for(;x<=m;x+=x&-x) c[x]+=d;} int query(int *c,int x) { int ans=0; for(;x;x-=x&-x) ans+=c[x]; return ans; } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d %d",&a[i].l,&a[i].r); t[i*2-1]=a[i].l; t[i*2]=a[i].r; } sort(a+1,a+n+1); sort(t+1,t+n*2+1); m=unique(t+1,t+n*2+1)-t-1; for(int i=0;i<=m;i++) { c1[i]=0; c2[i]=0; } for(int i=1;i<=n;i++) { a[i].l=lower_bound(t+1,t+m+1,a[i].l)-t; a[i].r=lower_bound(t+1,t+m+1,a[i].r)-t; } int ans=0; for(int i=1;i<=n;i++) modify(c2,a[i].l,1); for(int i=1;i<=n;i++) { ans=max(ans,query(c1,m)-query(c1,a[i].l-1)+query(c2,a[i].r)-query(c2,a[i].l-1)); modify(c2,a[i].l,-1); modify(c1,a[i].r,1); } printf("%d\n",n-ans); } return 0; }