传送门:http://codevs.cn/problem/4111/
线段树维护不是很好做取ln的操作
考虑均摊
正解是不递归为0的区间
因为一个数大概最多取4次ln就没了
所以暴力递归到底即可
均摊复杂度可以通过
【小优化:区间最大为1也可不递归】
我的做法比较套路了,对于一段区间取ln时
如果区间内最大值和最小值经过修改后,减小值相同,就可以用一个减法标记覆盖解决这个问题
这样做的话可以处理问题中有区间加减或者区间赋值之类的问题
以下为吐槽:
我……主程序i循环到了M,调了一天……结果顺带×掉了题解区的一份代码……
#include<bits/stdc++.h>
#define cint const int &
#define M 131072
#define Void inline void
#define Lson k<<1,l,mid
#define Rson k<<1|1,mid+1,r
using namespace std;
typedef long long ll;
int n,m,L,R;
ll ans;
struct node{int mx,mn,sz,tag;ll tot;}t[M<<1];
Void maintain(cint k)
{
if (!t[k].tag) return;
t[k]=(node){t[k].mx-t[k].tag,t[k].mn-t[k].tag,t[k].sz,t[k].tag,t[k].tot-(ll)t[k].sz*t[k].tag};
if (k<M) t[k<<1].tag+=t[k].tag,t[k<<1|1].tag+=t[k].tag;
t[k].tag=0;
}
Void merge(cint k)
{
maintain(k<<1),maintain(k<<1|1);
t[k]=(node){max(t[k<<1].mx,t[k<<1|1].mx),min(t[k<<1].mn,t[k<<1|1].mn),t[k<<1].sz+t[k<<1|1].sz,0,t[k<<1].tot+t[k<<1|1].tot};
}
void change(cint k,cint l,cint r)
{
maintain(k);
if (M<=k) return (void)(t[k]=(node){R,R,1,0,R});
int mid=l+r>>1;
if (L<=mid) change(Lson);else change(Rson);
merge(k);
}
inline int del(cint k){return k?k-(int)log(k):0;}
void atk(cint k,cint l,cint r)
{
maintain(k);
if (L<=l && r<=R && del(t[k].mx)==del(t[k].mn)) return (void)(t[k].tag+=del(t[k].mx));
int mid=l+r>>1;
if (L<=mid) atk(Lson);
if (mid<R) atk(Rson);
merge(k);
}
void find(cint k,cint l,cint r)
{
maintain(k);
if (L<=l && r<=R) return (void)(ans+=t[k].tot);
int mid=l+r>>1;
if (L<=mid) find(Lson);
if (mid<R) find (Rson);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=0,p;i<n;i++){scanf("%d",&p);t[i+M]=(node){p,p,1,0,p};}
for (int i=n;i<M;i++) t[i+M]=(node){-1,2033333333,0,0,0};
for (int i=M-1;i;i--) merge(i);
for (int type;m--;){
scanf("%d%d%d",&type,&L,&R);
if (type==1) change(1,1,M);
if (type==2) atk(1,1,M);
if (type==3) ans=0,find(1,1,M),printf("%lld\n",ans);
}
}