W
e
l
c
o
m
e
: )

计蒜客 A2285 / 2019ICPC徐州 H - Yuuki and a problem

右转学倍增值域分块

直接在神秘数的做法上大力树套树是 naive 的,考虑将值域分块的做法代入优化。

对于一个块 \([2^{k}, 2^{k+1})\) 内最小的数 \(m\),如果当前可以表示出的最大的数 \(x\ge m\),那么整个块内的元素都会被选(因为 \(x+m \ge m+2^{k}\ge 2^{k}+2^{k}=2^{k+1}\)),我们只需要维护区间内每个块的最小值和 \(sum\) 就行了,单点修改是容易的。

复杂度 \(O(n\log^2 n)\)

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset>
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
typedef pair <int, ll> Pil;
const int INF=0x3f3f3f3f;
const int cp=998244353;
inline int mod(int x){if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline void plust(int &x, int y){x=mod(x+y);return ;}
inline void minut(int &x, int y){x=mod(x-y);return ;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=2e5+5;
#define ls k<<1
#define rs k<<1|1
#define mid (l+r>>1)
int mn[N<<2][20];
ll sum[N<<2][20];
void pushup(int k){
	for(int i=0; i<20; ++i)
		mn[k][i]=min(mn[ls][i], mn[rs][i]),
		sum[k][i]=sum[ls][i]+sum[rs][i];
}
void update(int k, int l, int r, int x, int v){
	if(l==r){
		int t=__lg(v);
		for(int i=0; i<20; ++i) 
			mn[k][i]=(i^t)?INF:v, sum[k][i]=(i^t)?0:v;
		return ;	
	}
	if(x<=mid) update(ls, l, mid, x, v);
	else update(rs, mid+1, r, x, v);
	return pushup(k);
}
Pil operator + (Pil a, Pil b){return mp(min(a.st, b.st), a.nd+b.nd);}
Pil query(int k, int l, int r, int x, int y, int d){
	if(x>r||y<l||x>y) return mp(INF, 0ll);
	if(x<=l&&r<=y) return mp(mn[k][d], sum[k][d]);
	return query(ls, l, mid, x, y, d)+query(rs, mid+1, r, x, y, d);
}
#undef ls
#undef rs
#undef mid
int n, m;
signed main(){
	n=read(), m=read();
	for(int i=1; i<=n; ++i) update(1, 1, n, i, read());
	for(int i=1; i<=m; ++i){
		int op=read(), x=read(), y=read();
		if(op&1) update(1, 1, n, x, y);
		else{
			ll ans=0;
			for(int j=0; j<20; ++j){
				Pil t=query(1, 1, n, x, y, j);
				if(t.st<=ans+1) ans+=t.nd;
				else break;
			}
			printf("%lld\n", ans+1);
		}
	}
	return 0;
}
posted @ 2023-03-20 14:44  127_127_127  阅读(52)  评论(0编辑  收藏  举报