题解:P17738 [ICPC 2019 Xuzhou R] Yuuki and a problem
_Sorasaki_Hina_ · · 题解
树套树解法。
sol
考虑每个询问的答案是什么。
就是说
但是这个
换一个角度考虑,我们只需要关注这
考虑去做维护
显然
那我们从小到大一个一个去加不就行了,这显然是对的,但是复杂度不可接受。
其实发现你一次性把
然后可以证明对于一个区间去做这个往
因为上一轮把
分析完一通发现实现是简单的。观察查询实际上就是在做
每次查询你就把那个
但是真正上代码的时候你不能这么干,因为树套树查一次会把在
所以总时间是
然后就是注意树套树要回收废弃节点,要不然你空间就炸完了。
code
const int N = 2e5 + 2 ;
int n,q,a[N] ;
namespace ST {
int idx,hd ;
struct st {
int l,r ;
ll sum ;
}t[(int)2e7] ;
inline int newnode () {
if (!hd) return ++idx ;
else {
re int u = hd ;
hd = t[u].l,t[u].l = t[u].r = 0 ;
return u ;
}
}
inline void delnode (fi u) {t[u].l = hd,hd = u ;}
struct ST {
#define mid ((l + r) >> 1)
#define ls(x) (t[(x)].l)
#define rs(x) (t[(x)].r)
int rt ;
inline void update (int &u,fi l,fi r,fi x,fi k) {
if (!u) u = newnode() ;
t[u].sum += k ;
if (l == r) {
if (!t[u].sum) delnode(u),u = 0 ;
return ;
}
x <= mid ? update(ls(u),l,mid,x,k) : update(rs(u),mid + 1,r,x,k) ;
t[u].sum = t[ls(u)].sum + t[rs(u)].sum ;
if (!t[u].sum) delnode(u),u = 0 ;
}
inline ll query (fi u,fi l,fi r,fi L,fi R) {
if (!u || l > R || L > r || L > R) return 0 ;
if (L <= l && r <= R) return t[u].sum ;
re ll res = 0 ;
if (L <= mid) res += query(ls(u),l,mid,L,R) ;
if (R > mid) res += query(rs(u),mid + 1,r,L,R) ;
return res ;
}
}bit[N] ;
#define lb(x) ((x) & -(x))
inline void insert (int x,fi k,fi p) {
while (x <= n) bit[x].update(bit[x].rt,1,N,k,p),x += lb(x) ;
}
inline ll query (int l,int r,fi L,fi R) {
re ll res = 0 ;--l ;
while (l) res -= bit[l].query(bit[l].rt,1,N,L,R),l -= lb(l) ;
while (r) res += bit[r].query(bit[r].rt,1,N,L,R),r -= lb(r) ;
return res ;
}
}
inline void solve () {
read(n,q) ;
for (re int i = 1 ; i <= n ; ++i) read(a[i]),ST::insert(i,a[i],a[i]) ;
while (q--) {
re int op,x,y,l,r ;
re ll S = 0,tmp ;
read(op) ;
if (op == 1) {
read(x,y) ;
ST::insert(x,a[x],-a[x]) ;
a[x] = y ;
ST::insert(x,a[x],a[x]) ;
}
if (op == 2) {
read(l,r) ;
while (1) {
tmp = ST::query(l,r,1,min(1ll * N,S + 1)) ;
if (tmp== S) {
write(S + 1,endl) ;
break ;
}
S = tmp ;
}
}
}
}
int main () {
solve() ;
return 0 ;
}