给一个 T3 的不用主席树的简易做法。
建线段树,对每个点维护一个值 和一个有序 pair 列表,表示这个点对应的区间做完合并后,可以覆盖的区间为
,且剩余的待合并的数为
。
这个列表的意义是:如果 增大到某个不小于
的
,那么新的可覆盖区间会变成
,但这时仍然有
。
对于 的定义类似:如果
增大到某个不小于
的
,那么新的可覆盖区间会变成
,但这时仍然有
。对于
之类的可以类似定义下去。
这样定义之后,容易发现一个列表的长度至多是 ,因为
是两倍两倍增长的。而合并两个点的信息也只需要归并两个列表的信息。因此总的时间复杂度为
。
使用这个框架的另一个好处在于其可以方便地处理在线的询问,或者进行修改,如 2019 ICPC 徐州区域赛 H 题。
#include <bits/stdc++.h>
#define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp)
#define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> intpair;
int read(){
int f = 1, x = 0;
char c = getchar();
while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return f * x;
}
int n, m;
int a[100005], siz;
ll seg1[263000] = {0}, tmpv;
vector<intpair > seg2[263000], tmp, tmp2;
ll mmerge(ll xx1, ll xx2, vector<intpair >& v1, vector<intpair >& v2, vector<intpair >& res){
ll newx = xx1 + xx2 - 1;
int siz1 = v1.size(), siz2 = v2.size();
int lp = 0, rp = 0;
while (lp < siz1 || rp < siz2){
if (lp == siz1 || (rp < siz2 && v2[rp].first < v1[lp].first)){
// rp
if (v2[rp].first <= newx) newx += v2[rp].first + v2[rp].second;
else {
if (res.empty() || v2[rp].first > 2ll * res.back().first + res.back().second)
res.push_back(v2[rp]);
else res.back().second += v2[rp].first + v2[rp].second;
}
++rp;
} else {
if (v1[lp].first <= newx) newx += v1[lp].first + v1[lp].second;
else {
if (res.empty() || v1[lp].first > 2ll * res.back().first + res.back().second)
res.push_back(v1[lp]);
else res.back().second += v1[lp].first + v1[lp].second;
}
++lp;
}
}
return newx;
}
void init(){
n = read(), m = read();
REP(i, 1, n) a[i] = read();
for (siz = 1; siz < n; siz <<= 1) ;
REP(i, 1, n) {
if (a[i] == 1) seg1[i + siz - 1] = 2;
else seg1[i + siz - 1] = 1, seg2[i + siz - 1].push_back(make_pair(a[i], 0));
}
REP(i, siz + n, siz + siz - 1) seg1[i] = 1;
REPR(i, siz - 1, 1){
seg1[i] = mmerge(seg1[i << 1], seg1[i << 1 | 1], seg2[i << 1], seg2[i << 1 | 1],
seg2[i]);
}
}
int _a, _b;
void query(int id, int l, int r){
if (l > _b || r < _a) return ;
if (l >= _a && r <= _b){
tmp2.clear();
tmpv = mmerge(tmpv, seg1[id], tmp, seg2[id], tmp2);
tmp.clear();
for (const auto& p: tmp2) tmp.push_back(p);
return ;
}
int mid = (l + r) >> 1;
query(id << 1, l, mid);
query(id << 1 | 1, mid + 1, r);
}
void solve(){
while (m--){
_a = read(), _b = read();
tmpv = 1, tmp.clear();
query(1, 1, siz);
printf("%lld\n", tmpv);
}
}
int main(){
init();
solve();
return 0;
} 
京公网安备 11010502036488号