[CF1375H] Set Merging

[题目链接]

http://codeforces.com/contest/1375/problem/H

[题解]

考虑对值域分块。

不难发现对于一段值域在 \([l , r]\) 中对应的也是一段连续区间。

那么不妨对每一段记 \(f_{l , r}\) 表示 \([l , r]\) 这段区间对应的节点。

考虑建出一个类似于线段树的结构进行分治 , 每次递归处理小于 / 大于 \(mid\) 的数形成的集合。最后对跨过 \(mid\) 的进行合并即可。

这样做的复杂度 \(T(B) = 2T(\frac{B}{2}) + B ^ 2 \approx O(B ^ 2)\)

一共有 \(\frac{N}{B}\) 个块 , 故这部分复杂度 \(O(NB)\)

那么对于每个需求只需将其对应的每块值域的节点合并起来即可。

\(B\)\(\sqrt{N}\) 时 , 操作数约为 \(N\sqrt{N} \approx 2.2 * 10 ^ {6}\)

[代码]

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
 
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
 
typedef pair < int , int > pii;
#define mp make_pair
 
const int MN = 1e5 , MM = 2e6 , MS = 2.5e6 + 5 , MB = 1 << 8;
 
int A[MN] , rv[MN];
int N , M , siz , ans[MN] , B;
vector < pii > way;
 
inline int merge(int u , int v) {
	if (!u || !v) return u + v;
	way.emplace_back(mp(u , v));
	return ++siz;
}
 
int f[MB * 2 + 5][MB + 5][MB + 5];
 
struct Block {
	int l , r;
	inline void solve(int u , int l , int r , vector < int > V) {
		if (l == r) { f[u][1][1] = rv[V[1]]; return; }
		int mid = l + r >> 1; vector < int > LV(1) , RV(1);
		for (int i = 1; i < V.size(); ++i) 
			 if (V[i] <= mid) LV.emplace_back(V[i]);
			 else RV.emplace_back(V[i]);
		solve(u << 1 , l , mid , LV); solve(u << 1 | 1 , mid + 1 , r , RV);
		for (int i = 1 , xl = 1 , xr = 1; i < V.size(); xl += (V[i] <= mid) , xr += (V[i] > mid) , ++i) {
			for (int j = i - 1 , yl = xl - 1 , yr = xr - 1; j < V.size(); ++j , yl += (V[j] <= mid) , yr += (V[j] > mid)) {
				if (j == i - 1) continue;
				f[u][i][j] = merge(f[u << 1][xl][yl] , f[u << 1 | 1][xr][yr]);
			}
		}
	}
	int home[MN] , res[MB + 5][MB + 5];
	inline void build() {
		vector < int > vec(1);
		for (int i = 1; i <= N; ++i) 
			if (A[i] >= l && A[i] <= r) {
				vec.emplace_back(A[i]);
				home[i] = home[i - 1] + 1;
			} else home[i] = home[i - 1];
		solve(1 , l , r , vec);
		for (int i = 1; i < vec.size(); ++i)
		for (int j = 1; j < vec.size(); ++j)
			res[i][j] = f[1][i][j];
		return;
	}
	inline int query(int l , int r) {
		return res[home[l - 1] + 1][home[r]];
	}
} blo[20];
 
int main() {
	 
	 scanf("%d%d" , &N , &M); siz = N , B = min(N , MB);
	 for (int i = 1; i <= N; ++i) {
	 	 scanf("%d" , &A[i]);
	 	 rv[A[i]] = i;
	 }
	 for (int i = 1; (i - 1) * B + 1 <= N; ++i) {
	 	 blo[i].l = (i - 1) * B + 1 , blo[i].r = i * B;
		 blo[i].build(); 
	 }
	 for (int i = 1; i <= M; ++i) {
	 	 int l , r; scanf("%d%d" , &l , &r); ans[i] = 0;
	 	 for (int j = 1; j <= (N - 1) / B + 1; ++j)
	 	 	ans[i] = merge(ans[i] , blo[j].query(l , r));
	 }
	 printf("%d\n" , siz);
	 for (auto x : way)
	  	 printf("%d %d\n" , x.first , x.second);
	 for (int i = 1; i <= M; ++i)
	 	 printf("%d " , ans[i]);
	 printf("\n");
     return 0;
}
posted @ 2021-02-24 14:59  evenbao  阅读(61)  评论(0编辑  收藏  举报