1. 程式人生 > 實用技巧 >Codeforces1462F The Treasure of The Segments

Codeforces1462F The Treasure of The Segments

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;
}