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