【JZOJ5618】华胥梦天

Description
Description

Input
Input

Output
Output

Sample

Input:
10 10
4 9 5 9 4 4 4 7 3 5
3 4 10
2 39 35 39
3 37 34
2 26 16 31
2 28 19 31
1 19 28
3 27 28
3 23 26
3 12 9
3 8 11
Output:
36
25
18
15
12
12

Data Constraint
Data

Hint
Hint


Analysis

智术短浅,不会
然后眼看大佬们陆陆续续切掉了这道题。。。
好像只需要维护最大值,最大值的个数,次大值,答案,就好了,至于证明用势能分析。
涨姿势了

说说怎么做
设最大值为mx,次大值smx,最大值的个数t
单个位置更改,easy
区间对于x取min
xmx x ≥ m x ,不会做任何改变
smx<x<mx s m x < x < m x ,只需要打个tag
smxx s m x ≤ x ,就继续往下修改

怎么看怎么会炸啊
事实上并非如此
设势能 ϕ ϕ 等值于线段树上每一个子树的不同值的个数
一开始最坏情况下 ϕ=O(nlogn) ϕ = O ( n log ⁡ n )
单点修改 O(logn) O ( log ⁡ n ) ,势能最多 ϕ=ϕ+O(logn) ϕ = ϕ ′ + O ( log ⁡ n )
查询 O(1) O ( 1 ) ϕ=ϕ ϕ = ϕ ′
对于区间取min
xmx x ≥ m x ϕ=ϕ ϕ = ϕ ′
smx<x<mx s m x < x < m x ϕ=ϕ ϕ = ϕ ′
smxx s m x ≤ x ,至少使该个数减少1,多造成一次查找, ϕ=ϕO(1) ϕ = ϕ ′ − O ( 1 ) ,增加的查找次数只可能使得势能变为1,而势能最大仅为 O((n+m)logn) O ( ( n + m ) log ⁡ n ) 多造成查找的次数也是那么多,因此,总复杂度是 O(nlogn) O ( n log ⁡ n ) 的。

codes

#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 1000100
#define ll long long

using namespace std;

int n,m,a[N],nw,son[N][2],mx[N],smx[N],cnt[N],root,opl,opv,opr;
ll sum[N];
char ch[20];

ll read(){
    ll s=1,x=0;char c;for(;(c=getchar())<'0' || c>'9';)if(c=='-')s=-1;
    for(;c>='0' && c<='9';c=getchar()) x=(x<<1)+(x<<3)+c-48;return x*s;
}
void write(ll x){
    int j=0;for(;x>0;x/=10)ch[++j]=x%10+48;
    if(!j)ch[j=1]='0';while(j)putchar(ch[j--]);
    putchar('\n');
}

void update(int x){
    int l=son[x][0],r=son[x][1];sum[x]=sum[l]+sum[r];
    mx[x]=mx[l];cnt[x]=cnt[l];smx[x]=smx[l];
    if(mx[r]>mx[x]){
        if(smx[r]>mx[x])smx[x]=smx[r];else smx[x]=mx[x];
        mx[x]=mx[r];cnt[x]=cnt[r];
    }else if(mx[x]==mx[r]){
        cnt[x]+=cnt[r];if(smx[r]>smx[x])smx[x]=smx[r];
    }else if(mx[r]>smx[x])smx[x]=mx[r];
}
int build(int h,int t){
    int tmp=++nw,m=h+t>>1;
    if(h==t){
        mx[tmp]=smx[tmp]=a[h];cnt[tmp]=1;sum[tmp]=(ll)a[h];return tmp;
    }son[tmp][0]=build(h,m);son[tmp][1]=build(m+1,t);
    update(tmp);return tmp;
}
void dec(int w,int h,int t){
    if(h==t){
        int k=max((int)sum[w]-opv,0);
        sum[w]=(ll)k;mx[w]=smx[w]=k;return;
    }int m=h+t>>1;
    if(m>=opl)dec(son[w][0],h,m);else dec(son[w][1],m+1,t);
    update(w);
}
void lower(int w,int h,int t){
    if(opl<=h && opr>=t){
        if(mx[w]<=opv)return;
        if(smx[w]<opv){sum[w]-=(ll)(mx[w]-opv)*(ll)(t-h+1);mx[w]=opv;return;}
    }
    if(h==t){
        mx[w]=smx[w]=opv;sum[w]=(ll)opv;return;
    }int m=h+t>>1;
    if(m>=opl)lower(son[w][0],h,m);if(m<opr)lower(son[w][1],m+1,t);
    update(w);
}
ll query(int w,int h,int t){
    if(opl<=h && opr>=t)return sum[w];int m=h+t>>1;ll r=0;
    if(m>=opl)r+=query(son[w][0],h,m);if(m<opr)r+=query(son[w][1],m+1,t);return r;
}

int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)a[i]=read();root=build(1,n);
    ll las=0;
    for(int i=1;i<=m;i++){
        ll s=read(),l=read(),r,x;l^=las;
        if(s==1){
            x=read();x^=las;opl=l;opv=x;dec(root,1,n);
        }
        if(s==2){
            r=read();x=read();x^=las;r^=las;opl=l;opr=r;opv=x;lower(root,1,n);
        }
        if(s==3){
            r=read();r^=las;opl=l;opr=r;write(las=query(root,1,n));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值