Codeforces 1462F。セグメントの宝(貪欲でツリー配列)

F.セグメントの宝物

テストごとの制限時間

3秒

テストごとのメモリ制限

256メガバイト

入力

標準入力

出力

標準出力

ポリュカルポスは通りでnn個のセグメントを見つけました。インデックスiiのセグメントは、2つの整数liliとriri(それぞれ、セグメントの開始と終了の座標)で記述されます。ポリュカルポスは、すべてのセグメントが必要ではないことに気付いたため、一部のセグメントを削除したいと考えました。

ポリュカルポスは、セットからのセグメント[li、ri] [li、ri](1≤i≤k1≤i≤k)があり、セットからのすべてのセグメントと交差する場合、kkセグメントのセットは適切であると考えています(交点は点またはセグメントである必要があります)。たとえば、33個のセグメント[[1,4]、[2,3]、[3,6]] [[1,4]、[2,3]、[3,6]]のセットは適切です。セグメント[2,3] [2,3]は、セットの各セグメントと交差します。44セグメントのセット[[1,2]、[2,3]、[3,5]、[4,5]] [[1,2]、[2,3]、[3,5]、[4 、5]]は良くありません。

ポリュカルポスは、残りのセグメントが適切なセットを形成するために削除しなければならないセグメントの最小数はいくつですか?

入力

最初の行には、単一の整数tt(1≤t≤2⋅1051≤t≤2⋅105)—テストケースの数が含まれています。次に、ttテストケースが続きます。

各テストケースの最初の行には、単一の整数nn(1≤n≤2⋅1051≤n≤2⋅105)(セグメントの数)が含まれています。この後に、セグメントを説明するnn行が続きます。

各セグメントは、2つの整数llとrr(1≤l≤r≤1091≤l≤r≤109)—それぞれセグメントの開始と終了の座標で記述されます。

すべてのテストケースのnnの合計が2⋅1052⋅105を超えないことが保証されています。

出力

テストケースごとに、単一の整数を出力します。これは、残りのセグメントのセットが適切になるために削除する必要があるセグメントの最小数です。

入力

コピー

4 
3 
1 4 
2 3 
3 6 
4 
1 2 
2 3 
3 5 
4 5 
5 
1 2 
3 8 
4 5 
6 7 
9 10 
5 
1 5 
2 4 
3 5 
3 8 
4 8

出力

コピー

0 
1 
2 
0

本旨:

N個のラインセグメントがあり、ラインセグメントセットは適切です。セット内のすべてのラインセグメントと交差できるラインセグメントがセット内に少なくとも1つある場合にのみ、残りのラインセグメントが適切なセットを形成できるように、最も少ないラインセグメントを削除します。削除の最小数を出力します。

解決:

質問は、各ラインセグメントと交差するラインセグメントの数を尋ねることに変換されます。

まず、各ラインセグメントの端点のみを確認します。特定のラインセグメントの場合、間隔に表示されるエンドポイントの数は、交差するラインセグメントの数を表します。特定のラインセグメントの両方の端点が内側にある場合、答えは間違っているため、必要です。分類するには、最初に左端点を追加してから、右端点を追加します。この時点でアイデアが出てきました。左右のエンドポイントの順序に従って、最初に各ラインセグメントに含まれる左エンドポイントの数にアクセスし、次に後方にトラバースして含まれる右エンドポイントの数を確認し、中央にツリー配列を配置して維持します。

受け入れられたコード

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

struct node
{
	int l, r;
	bool operator < (const node &oth) const {
		if (r == oth.r)
			return l < oth.l;
		else
			return r < oth.r;
	}
}a[N];
int s[N * 2], ans[N], n, sz;
vector <int> ver;

void Init() {
	for (int i = 1; i <= sz; i++)
		s[i] = 0;
	ver.clear();
}
void Add(int x, int v) {
	while (x <= sz)
		s[x] += v, x += lowbit(x);
}
int Ask(int x) {
	int tot = 0;
	while (x)
		tot += s[x], x -= lowbit(x);
	return tot;
}
int Rg_Ask(int l, int r) {
	return Ask(r) - Ask(l - 1); 
}

int main()
{
#ifdef OlaMins
	freopen("D:/input.txt", "r", stdin);
	//freopen("D:/output.txt", "w", stdout);
#endif

	int T; cin >> T;
	while (T--) {
		sc("%d", &n);
		Init();

		for (int i = 1; i <= n; i++) {
			int l, r;
			sc("%d %d", &l, &r);
			ver.push_back(l), ver.push_back(r);
			a[i] = { l, r }, ans[i] = 0;
		}
		sort(ALL(ver));
		ver.erase(unique(ALL(ver)), ver.end());  // 离散化
		sz = SZ(ver);

		for (int i = 1; i <= n; i++) {
			a[i].l = lower_bound(ALL(ver), a[i].l) - ver.begin() + 1;
			a[i].r = lower_bound(ALL(ver), a[i].r) - ver.begin() + 1;
		}
		sort(a + 1, a + n + 1);

		for (int i = 1; i <= n; i++) {  // 先左
			int l = a[i].l, r = a[i].r;
			ans[i] = Rg_Ask(l, r);
			Add(r, 1);
		}

		for (int i = 1; i <= sz; i++)
			s[i] = 0;
		int mi = INF;
		for (int i = n; i >= 1; i--) {   // 后右
			int l = a[i].l, r = a[i].r;
			ans[i] += Rg_Ask(l, r);
			Min(mi, n - ans[i]);
			Add(l, 1);
		}
		printf("%d\n", mi - 1);
	}
	return 0; // 改数组大小!!!用pair改宏定义!!!
}

 

おすすめ

転載: blog.csdn.net/weixin_43851525/article/details/111384943