洛谷题目传送门
闲话
考场上一眼看出这是个毒瘤线段树准备杠题,发现实在太难调了,被各路神犇虐哭qwq
考后看到各种优雅的暴力AC。。。。。。宝宝心里苦qwq
思路分析
题面里面是一堆乱七八糟的限制和性质,这时候需要冷静想想有没有可利用的地方。蒟蒻一开始往势能线段树上面想了想。
定义一个全局势能函数,为所有\(C_i
一个是改\(A\),相当于对\(C\)进行区间设置,此时我们每暴力找到一个原来\(C_i
一个是改\(B\),是单点修改,线段树内跳\(\log\)层,势能函数至多加\(1\)。
于是,如果我们能够维护信息,从而判断和控制哪里该暴力递归、哪里该跳过的话,我们总的在线段树内跳的次数不会超过\((n+q)\log n\)。
下面用a代替了\(C\),b代替了\(B\)。蒟蒻在线段树里维护了:
- pa:区间所有a
- pb:区间所有a>=b的位置的b的积
- ma:区间a的最大值
- mb:区间所有a
- cnt:区间所有a
- la:bool型变量,区间设置懒标记
修改a的时候,利用单调不降的性质,我们在线段树上先通过二分来对需要修改的若干个子树进行定位。对于当前子区间,如果当前设置值\(y\)比mb要小,那么设置对答案没有影响,直接打上区间设置标记后退出;否则继续递归直到找到叶子节点,进行修改后退出。
修改b就比较轻松,只要找到对应的叶子节点改完后一路回溯即可。
很多事都是说起来容易做起来难,这题也不例外。调试几乎花了整个晚上。要注意的细节很多,也只好自己仔细思考了。
时间复杂度\(O(n\log n+q\log^2n)\),上界很松。多出来的\(\log\)是区间改a时需要快速幂更新pa造成的。
跑了不到200ms,比什么树套树、分块还是要好看一点,但是被暴力碾压也是有点无奈啊~
#include
#define RG register
#define R RG int
#define I inline
#define G if(++ip==ie)fread(ip=buf,1,N,stdin)
using namespace std;
typedef long long LL;
const LL N=1<<18,YL=1e9+7;
char buf[N],*ie=buf+N,*ip=ie-1;
int y,a[N];
I int in(){
G;while(*ip<'-')G;
R x=*ip&15;G;
while(*ip>'-'){x*=10;x+=*ip&15;G;}
return x;
}
I LL qpow(RG LL b,R k){//快速幂
RG LL a=1;
for(;k;k>>=1,(b*=b)%=YL)
if(k&1)(a*=b)%=YL;
return a;
}
struct Node{//个人认为写指针比较直观(貌似immortalCO也有这样的看法)
Node*lc,*rc;bool la;
LL pa,pb;int l,r,m,ma,mb,cnt;
I void up(){//上传
pa=lc->pa*rc->pa%YL;
pb=lc->pb*rc->pb%YL;
ma=max(lc->ma,rc->ma);
mb=min(lc->mb,rc->mb);
cnt=lc->cnt+rc->cnt;
}
I void dn(){//下传区间设置标记
if(la){
lc->ma=rc->ma=ma;
lc->la=rc->la=1;la=0;
lc->pa=qpow(ma,lc->cnt);
rc->pa=qpow(ma,rc->cnt);
}
}
I void build(R s,R e){//建树
l=s;r=e;m=(s+e)>>1;la=0;
if(s==e){
ma=a[l];mb=in();
(cnt=mabuild(l,m);
(rc=new Node)->build(m+1,r);
this->up();
}
I void upda(){//区间修改a
if(ydn();
lc->upda();rc->upda();
this->up();
}
I void updb(R s){//单点更新b
if(l==r){//仔细判断三种情况再修改
if(madn();
(s<=m?lc:rc)->updb(s);
this->up();
}
I void bound(R s){//线段树二分定位,注意细节
if(s==l&&maupda();
if(l==r)return;
this->dn();
if(lc->mabound(m+1);
lc->bound(s);
this->up();
}
};
int main(){
R n=in(),q=in(),op,x;
for(R i=1;i<=n;++i)a[i]=max(a[i-1],in());
RG Node rt;rt.build(1,n);
while(q--){
op=in();x=in();y=in();
op?rt.updb(x):rt.bound(x);
printf("%lld\n",rt.pa*rt.pb%YL);
}
return 0;
}