class BIT
{
int n = 2e6;
long long *a;
public:
BIT(int size) : n(size)
{
a = new long long[size + 10];
}
void update(int p, long long x)
{
while (p <= n)
a[p] += x, p += (p & (-p));
}
long long query(int l, int r)
{
long long ret = 0;
l--;
while (r > 0)
ret += a[r], r -= (r & (-r));
while (l > 0)
ret -= a[l], l -= (l & (-l));
return ret;
}
};
template<typename T>
struct Fenwick{
int n;
vector<T> tr;
Fenwick(int n) : n(n), tr(n + 1, 0){}
int lowbit(int x){
return x & -x;
}
void modify(int x, T c){//单点添加
for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}
void modify(int l, int r, T c){//区间添加
modify(l, c);
if (r + 1 <= n) modify(r + 1, -c);
}
T query(int x){
T res = T();
for(int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
T query(int l, int r){
return query(r) - query(l - 1);
}
int find_first(T sum){//和出现的第一位置
int ans = 0; T val = 0;
for(int i = __lg(n); i >= 0; i--){
if ((ans | (1 << i)) <= n && val + tr[ans | (1 << i)] < sum){
ans |= 1 << i;
val += tr[ans];
}
}
return ans + 1;
}
int find_last(T sum){
int ans = 0; T val = 0;
for(int i = __lg(n); i >= 0; i--){
if ((ans | (1 << i)) <= n && val + tr[ans | (1 << i)] <= sum){
ans |= 1 << i;
val += tr[ans];
}
}
return ans;
}
};
using BIT = Fenwick<int>;
struct DSU
{
vector<int> f;
DSU() {}
DSU(int n)
{
clear(n);
}
// 多测时只构造一次 清空T次
void clear(int n)
{
f.resize(n);
iota(f.begin(), f.end(), 0);
}
int find(int x)
{
return f[x] == x ? x : (f[x] = find(f[x]));
}
bool same(int x, int y)
{
return find(x) == find(y);
}
bool merge(int x, int y)
{
x = find(x);
y = find(y);
return (x == y) ? false : f[y] = x;
}
};
struct DSU
{
vector<int> f, siz;
DSU() {}
DSU(int n)
{
clear(n);
}
void clear(int n)
{
f.resize(n);
iota(f.begin(), f.end(), 0);
siz.assign(n, 1);
}
int find(int x)
{
return f[x] == x ? x : (f[x] = find(f[x]));
}
bool same(int x, int y)
{
return find(x) == find(y);
}
bool merge(int x, int y)
{
x = find(x);
y = find(y);
if (x == y)
return false;
// if (siz[x] < siz[y])
// swap(x, y);
siz[x] += siz[y];
f[y] = x;
return true;
}
int size(int x)
{
return siz[find(x)];
}
};
// log2(x) 的预处理
// 1. 递推
lg[2] = 1;
for (int i = 3; i < N; i++)
lg[i] = lg[i / 2] + 1;
// 2. 基于编译期计算
using std::array;
// WARNING: LOG_SIZE may cause CE if too big.
const int LOG_SIZE = 1e5 + 10;
constexpr array<int, LOG_SIZE> LOG = []() {
array<int, LOG_SIZE> l{0, 0, 1};
for (int i = 3; i < LOG_SIZE; i++)
l[i] = l[i / 2] + 1;
return l;
}();
// 3. 直接计算
int lg(int x)
{
return 31 - __builtin_clz(x);
}
// STL 提供了 std::lg(), 底数是e.
class SparseTable
{
private:
// SIZE depends on range of f[i][0].
// 22 is suitable for 1e5.
static const int SIZE = 22;
// f[i][j] maintains the result from i to i + 2 ^ j - 1;
int (*f)[SIZE];
using func = std::function<int(int, int)>;
func op;
// length of f from 1 to l;
int l;
public:
SparseTable(int a[][SIZE], func foo, int len) : f(a), op(foo), l(len)
{
for (int j = 1; j < SIZE; j++)
for (int i = 1; i + (1 << j) - 1 <= len; i++)
// f[i][j] comes from f[i][j - 1].
// f[i][j - 1], f[i + 2^(j - 1)] cover the range of f[i][j].
f[i][j] = foo(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
};
int query(int x, int y)
{
int s = LOG[y - x + 1];
return op(f[x][s], f[y - (1 << s) + 1][s]);
}
};
const int N = 1e6;
int a[N];
int tag[4 * N];
int tree[4 * N];
int n;
void push_up(int p)
{
tree[p] = tree[ls(p)] + tree[rs(p)];
}
void build(int p, int l, int r)
{
if (l == r)
{
tree[p] = a[l];
return;
}
int mid = (l + r) >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
push_up(p);
}
void push_down(int p, int l, int r)
{
int mid = (l + r) >> 1;
tag[ls(p)] += tag[p];
tag[rs(p)] += tag[p];
tree[ls(p)] += tag[p] * (mid - l + 1);
tree[rs(p)] += tag[p] * (r - mid);
tag[p] = 0;
}
void update(int nl, int nr, int k, int p = 1, int l = 1, int r = n)
{
if (nl <= l && r <= nr)
{
tag[p] += k;
tree[p] += k * (r - l + 1);
return;
}
push_down(p, l, r);
int mid = (l + r) >> 1;
if (nl <= mid)
update(nl, nr, k, ls(p), l, mid);
if (nr > mid)
update(nl, nr, k, rs(p), mid + 1, r);
push_up(p);
}
int query(int x, int y, int l = 1, int r = n, int p = 1)
{
int res = 0;
if (x <= l && y >= r)
return tree[p];
int mid = (l + r) >> 1;
push_down(p, l, r);
if (x <= mid)
res += query(x, y, l, mid, ls(p));
if (y > mid)
res += query(x, y, mid + 1, r, rs(p));
return res;
}
int main()
{
int q;
cin >> n >> q;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
while (q--)
{
int op, x, y, k;
cin >> op;
if (op == 1)
{
cin >> x >> y >> k;
update(x, y, k);
}
else
{
cin >> x >> y;
cout << query(x, y) << endl;
}
}
return 0;
}
eg. 两种操作,1. 修改ai为d 2. 查询l,r中第一次出现大于等于d位置,否则返回-1
维护区间最大值,
对一个区间判断最大值是否大于等于d
存在则先找左区间,再找右区间
struct node
{
int maxn;
} tree[800005];
int n;
int tag[800005];
void push_down(int p, int l, int r)
{ // 标记下压
int mid = (r + l) / 2;
tree[2 * p].maxn += tag[p];
tree[2 * p + 1].maxn += tag[p];
tag[2 * p] += tag[p];
tag[2 * p + 1] += tag[p];
tag[p] = 0;
}
void update(int l, int r, int k, int cl = 1, int cr = n, int p = 1)
{ // 更新
if (cl > r || cr < l)
{
return;
}
if (cl >= l && cr <= r)
{
tree[p].maxn += k;
if (cl < cr)
{
tag[p] += k;
}
}
else
{
int mid = (cl + cr) >> 1;
push_down(p, cl, cr);
if (l <= mid)
update(l, r, k, cl, mid, 2 * p);
if (r > mid)
update(l, r, k, mid + 1, cr, 2 * p + 1);
tree[p].maxn = max(tree[p << 1].maxn, tree[p * 2 + 1].maxn);
}
}
int query(int l, int r, int cl = 1, int cr = n, int p = 1)
{ // 查询
if (cl >= l && cr <= r)
{
return tree[p].maxn;
}
else
{
int mid = (cl + cr) >> 1;
push_down(p, cl, cr);
int tmp = 0;
if (l <= mid)
tmp = max(tmp, query(l, r, cl, mid, 2 * p));
if (r > mid)
tmp = max(tmp, query(l, r, mid + 1, cr, 2 * p + 1));
return tmp;
}
}
满足栈中元素单调递增或递减的栈
可用于o(n)寻找每个数之后第一个大于他的数的位置(用单调递减栈)
可解决求
即区间长度乘区间最值结果的最值
int n,m;//洛谷P5788
stack<int>st;
int a[3000005],ans[3000005];
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
while(st.size()&&a[i]>a[st.top()]){//维护递减栈
ans[st.top()] = i;//更新答案
st.pop();
}
st.push(i);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
cout<<endl;
}
p[head]表示序号 p[head]!=head
int p[N];
int head=1,tail=0;
for(int i=1;i<=n;i++){
if(head<=tail&&p[head]==i-k){//当前0 区间长度大于k时扔掉头部
head++;
}
while(head<=tail&&a[p[tail]]<=a[i]) tail--;//此时求最大值
p[++tail]=i;
//则head记录区间内最值
}
struct node
{
int l, r;
ll v;
} tr[N];
ll a[N];
int tot;
int clone(int x)
{
tr[++tot] = tr[x];
return tot;
}
int push_up(int p)
{
tr[p].v = tr[tr[p].l].v + tr[tr[p].r].v;
return p;
}
int build(int l, int r)
{
int x = ++tot;
if (l == r)
{
tr[x].v = a[l];
return x;
}
int mid = (l + r) / 2;
tr[x].l = build(l, mid);
tr[x].r = build(mid + 1, r);
return push_up(x);
}
int update(int pos, int l, int r, int x, int p)
{
int np = clone(p);
if (l == r)
{
tr[np].v = x;
return np;
}
int mid = (l + r) / 2;
if (pos <= mid)
tr[np].l = update(pos, l, mid, x, tr[np].l);
else
tr[np].r = update(pos, mid + 1, r, x, tr[np].r);
return push_up(np);
}
ll query(int l, int r, int x, int y, int p)
{
if (l >= x && r <= y)
return tr[p].v;
int mid = (l + r) / 2;
if (y <= mid)
return query(l, mid, x, y, tr[p].l);
else if (x > mid)
return query(mid + 1, r, x, y, tr[p].r);
return query(l, mid, x, mid, tr[p].l) + query(mid + 1, r, mid + 1, y, tr[p].r);
}
struct pree_kth
{
int tot = 0;
int size;
vector<node> tr;
vector<int> his;
map<int, int> to, back;
int clone(int x)
{
tr[++tot] = tr[x];
return tot;
}
int push_up(int p)
{
tr[p].v = tr[tr[p].l].v + tr[tr[p].r].v;
return p;
}
pree_kth(vector<int> &a, int n) : his(n + 1), tr(n << 5), size(n)
{
map<int, int> mp;
int cnt = 0;
for (int i = 1; i <= n; i++)
mp[a[i]]++;
for (auto [k, v] : mp)
to[k] = ++cnt, back[cnt] = k;
his[0] = build(1, n);
for (int i = 1; i <= n; i++)
his[i] = update(to[a[i]], 1, n, his[i - 1]);
}
int build(int l, int r)
{
int x = ++tot;
if (l == r)
{
tr[x].v = 0;
return x;
}
int mid = (l + r) / 2;
tr[x].l = build(l, mid);
tr[x].r = build(mid + 1, r);
return push_up(x);
}
int update(int pos, int l, int r, int p)
{
int np = clone(p);
if (l == r)
{
tr[np].v++;
return np;
}
int mid = (l + r) / 2;
if (pos <= mid)
tr[np].l = update(pos, l, mid, tr[np].l);
else
tr[np].r = update(pos, mid + 1, r, tr[np].r);
return push_up(np);
}
int _get(int u, int v, int l, int r, int k)
{
if (l == r)
return l;
int x = tr[tr[v].l].v - tr[tr[u].l].v;
int mid = (l + r) / 2;
if (x >= k)
return _get(tr[u].l, tr[v].l, l, mid, k);
else
return _get(tr[u].r, tr[v].r, mid + 1, r, k - x);
}
int kth(int l, int r, int k)
{
return back[_get(his[l - 1], his[r], 1, size, k)];
}
};