计蒜客 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;
}