【CODE[VS]】4111 TTY Saves Da’shgua (月赛round2)

传送门: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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值