Codeforces 1375 H : Set Merging

做了一天 Global 9 做吐了,全是构造属实有毒啊。

考虑在低于 \(n^3\) 的复杂度做出来这个东西:

考虑求所有区间。我们可以将其拆成值域 \([1,\text{mid}]\)\([\text{mid}+1, r]\) 两个序列,然后对每个区间将小于等于 \(mid\) 和大于 \(mid\) 的部分合并起来。

这样的次数是: \(f(n) = 2*f(\frac{n}{2})+ \frac{n^2}{2}\) 。可以分析出来,这个东西实际上是 \(n^2\) 次的。

然而直接 \(n^2\) 并不能通过,剩下的也很简单:考虑询问不多,我们将序列按值的大小拆成 \(t\) 个序列,每次 \(t\) 次合并完成一个询问。

\(t\)\(16\) 即可。次数大概是: \((\frac{4096}{16})^2*16+65536*16 = 2097152\) 次。就过了。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int cnt;
const int N = (1<<12)+20;
vector < vector<int> >  Block[17];
vector < pair<int,int> > operators;
inline int merge(int a,int b){
	if(!a||!b)return a|b;
	operators.push_back(make_pair(a,b));
	return ++cnt;
}
int Limit;
int num;
int bel[N];
int a[N];
inline vector< vector<int> > get_idx(vector<int> idx, int all_rngs){
	int n = idx.size()-1;
	if(all_rngs==Limit){
		++num; for(int i=1;i<=n;i++)bel[idx[i]] = num;
	}
	if(all_rngs<Limit){
		vector<int> b;for(int i=1;i<=n;i++)b.push_back(a[idx[i]]);
		sort(b.begin(),b.end());
		int Split_Number=b[n/2-1];
		vector<int> Lft(1,0), Rgt(1,0);
		for(int i=1;i<=n;i++)
			if(a[idx[i]]<=Split_Number)Lft.push_back(idx[i]);
			else Rgt.push_back(idx[i]);
		vector < vector<int> > L = get_idx(Lft, all_rngs*2);
		vector < vector<int> > R = get_idx(Rgt, all_rngs*2);
		return vector< vector<int> >();
	}
	vector< vector<int> > ret(n+2, vector<int>(n+2));
	if(n==1){ret[1][1]=idx[1];}
	else{
		vector<int> b;for(int i=1;i<=n;i++)b.push_back(a[idx[i]]);
		sort(b.begin(),b.end());
		int Split_Number=b[n/2-1];
		vector<int> Lft(1,0), Rgt(1,0);
		for(int i=1;i<=n;i++)
			if(a[idx[i]]<=Split_Number)Lft.push_back(idx[i]);
			else Rgt.push_back(idx[i]);
		vector < vector<int> > L = get_idx(Lft, all_rngs*2);
		vector < vector<int> > R = get_idx(Rgt, all_rngs*2);
		vector<int> pref[2];pref[0]=pref[1]=vector<int>(n+1,0);
		for(int i=1;i<=n;i++){
			pref[0][i]=pref[0][i-1], pref[1][i]=pref[1][i-1];
			if(a[idx[i]]<=Split_Number)pref[0][i]++;
			else pref[1][i]++;
		}
		for(int i=1;i<=n;i++)for(int j=i;j<=n;j++){
			if(i==j)ret[i][j]=idx[i];
			else{
				ret[i][j]=merge(L[pref[0][i-1]+1][pref[0][j]],R[pref[1][i-1]+1][pref[1][j]]);
			}
		}
	}
	if(all_rngs==Limit){Block[num]=ret;}
	return ret;
}

int pref[17][N];

int main()
{
	cin >> n >> m;cnt=n;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	Limit=1;while(Limit*2<=n&&Limit<16)Limit<<=1;
	vector<int> q(1,0);
	for(int i=1;i<=n;i++)q.push_back(i);
	get_idx(q,1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=num;j++)pref[j][i]=pref[j][i-1];
		pref[bel[i]][i]++;
	}
	vector<int> ans;
	while(m--){
		int l,r;scanf("%d%d",&l,&r);
		int cur=0;
		for(int i=1;i<=num;i++){
			int _l=pref[i][l-1]+1, _r=pref[i][r];
			cur=merge(cur,Block[i][_l][_r]);
		}
		ans.push_back(cur);
	}
	cout << cnt << endl;
	for(size_t i=0;i<operators.size();i++){
		printf("%d %d\n", operators[i].first, operators[i].second);
	}
	for(size_t i=0;i<ans.size();i++)printf("%d ", ans[i]);puts("");
	return 0;
}
posted @ 2020-07-07 23:12  jerome_wei  阅读(296)  评论(0编辑  收藏  举报