UOJ515 前进四(扫描线+势能线段树)

考虑以时间为下标,数组下标从 $n$ 至 $1$ 扫描,那么 $a_i$ 在 $t_1-t_2$ 时刻的值为 $val$ 对应的修改应为对 $t_1-t_2$ 区间取 $\min$。而查询操作对应的就是查询 $t$ 这个位置被更新了多少次。

考虑势能线段树维护。因为不同的 $val$ 不超过 $n+t$ 个,所以时间复杂度为 $O((n+t)\log t)$。

欸我怎么 85/97 啊?注意一下卡常点:

  1. 询问是单点查询,从上到下 pushdown 常数很大,要用 zkw 线段树的写法从下往上加;
  2. vector 插入是真的慢($n=10^6$ 时光插入就要0.8s),要手写链表;
  3. puhsup/pushdown 可以考虑手工内联;
  4. 各种奇奇怪怪的卡常技巧。

 

#include<cstdio>
#define For(i,A,B) for(i=(A);i<=(B);++i)
const int N=1000050;
const int BUF=1<<23;
char rB[BUF],*rS,*rT,wB[BUF],*wT=wB;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wT-wB,stdout);wT=wB;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[15];
inline void wt(int x){
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    *wT++=x|48;
    while(l>=0)*wT++=buf[l--]|48;
    *wT++='\n';
}
int mx[N<<2],mx2[N<<2],tag[N<<2],ps[N],s[N],chd[N],qhd[N],tim[N<<1],val[N<<1],nxt[N<<1],x,y,v,tot;
inline int Max(int a,int b){return a>b?a:b;}
inline void ins(int *hd,int x,int tm,int vl){
    tim[++tot]=tm;val[tot]=vl;nxt[tot]=hd[x];hd[x]=tot;
}
void build(int o,int L,int R){
    mx[o]=0x3f3f3f3f;
    if(L<R){
        int lc=o<<1,rc=lc|1,M=L+R>>1;
        build(lc,L,M);build(rc,M+1,R);
    }else ps[L]=o;
}
void update(int o,int L,int R){
    if(x<=L&&y>=R&&v>mx2[o]){
        if(v<mx[o]){mx[o]=v;++tag[o];}
        return;
    }
    int lc=o<<1,rc=lc|1,M=L+R>>1;
    if(tag[o]){
        int lc=o<<1,rc=lc|1;
        if(mx[o]<mx[lc]){mx[lc]=mx[o];tag[lc]+=tag[o];}
        if(mx[o]<mx[rc]){mx[rc]=mx[o];tag[rc]+=tag[o];}
        tag[o]=0;
    }
    if(x<=M)update(lc,L,M);
    if(y>M)update(rc,M+1,R);
    if(mx[lc]==mx[rc]){mx[o]=mx[lc];mx2[o]=Max(mx2[lc],mx2[rc]);}
    else if(mx[lc]>mx[rc]){mx[o]=mx[lc];mx2[o]=Max(mx2[lc],mx[rc]);}
    else{mx[o]=mx[rc];mx2[o]=Max(mx[lc],mx2[rc]);}
}
inline int query(int x){
    int o=ps[x],s=tag[o],val=mx[o];
    for(o>>=1;o;o>>=1)if(mx[o]<val){s+=tag[o];val=mx[o];}
    return s;
}
int main(){
    int n=rd(),q=rd(),i,j,opt,ccnt=0,qcnt=-1;
    bool lq=0;
    For(i,1,n)ins(chd,i,0,rd());
    while(q--){
        opt=rd();x=rd();
        if(opt==1){
            if(lq){++ccnt;lq=0;}
            ins(chd,x,ccnt,rd());
        }else{
            ins(qhd,x,ccnt,++qcnt);
            lq=1;
        }
    }
    build(1,0,ccnt);
    for(i=n;i;--i){
        for(y=ccnt,j=chd[i];j;j=nxt[j]){
            if((x=tim[j])<=y){
                v=val[j];
                update(1,0,ccnt);
            }
            y=x-1;
        }
        for(j=qhd[i];j;j=nxt[j])s[val[j]]=query(tim[j]);
    }
    For(i,0,qcnt)wt(s[i]);
    flush();
    return 0;
}
View Code

 

posted @ 2020-04-07 10:13  wangyuchen  阅读(351)  评论(0编辑  收藏  举报