bzoj4695: 最假女选手 //吉利线段树

bzoj4695: 最假女选手


题意

给出长为N(<=5e5)的序列,要求支持区间加、区间取min/max、区间求和、区间求min/max。


题解

我 好久好久以前 就想学这个科技…
O ( n l o g 2 n ) S e g m e n t T r e e B e a t s !
区间取min/max时,对于被包含的区间,如果可以只更改min/max的值,那么直接修改,否则暴力dfs下去。
其他操作不变。
听说课件里那个单log的证明有锅?
照本宣科一发。

势能函数定义为线段树里最值异于其父节点最值的节点个数。
以区间对v取min为例。
终止节点只有 v >= m a x s e c < v < m a x
第一种的兄弟节点一定是被访问过的非终止节点或第二种终止节点,所以这个我们不考虑。
第二种终止节点在取min后的max和父节点的max相等。
因此势能函数减少 A ,对复杂度的贡献是 A l o g N
区间加涉及 l o g n 个节点,因此势能函数最多增加 M l o g N
所以总复杂度是 M l o g 2 N

这么说起来,50w 双log 真是信仰式复杂度。。


代码

为什么我跑得这么慢!这么慢!!
刚开始每个点比std慢了0.5s左右。。
在奇怪的地方卡了下常…函数能不调用就尽量不要调用,在外面判会比在里面判快很多…
真是强行加长代码(

#include<cstdio>
#define N 500005
#define mid (l+r>>1)
#define inf 0x3f3f3f3f
#define pu sum[k]=sum[k<<1]+sum[k<<1|1],upd(k,0),upd(k,1)
#define cmp(x,y) (d?x<y:(x>y))
#define P(x) ad[k]?add(k<<1|x,ad[k]):(void)0,fm[0][k<<1|x]<fm[0][k]?mini(k<<1|x,fm[0][k],1):(void)0,fm[1][k<<1|x]>fm[1][k]?mini(k<<1|x,fm[1][k],0):(void)0
#define pd P(0),P(1),ad[k]=0
using namespace std;
typedef long long LL;
int f,c,v;
inline void rd(int &x)
{
    while((c=getchar()-'0')^-3&&c<0|c>9);
    c^-3?x=c,f=0:(f=1,x=0);
    for(;(c=getchar()-'0')>=0&&c<=9;x=(x<<3)+(x<<1)+c);
    x=f?-x:x;
}
LL sum[N<<2];
int n,m,ll,rr,len[N<<2],
fm[2][N<<2],fc[2][N<<2],se[2][N<<2],ad[N<<2];
inline void add(int x,int y)
{fm[0][x]+=y,fm[1][x]+=y,se[0][x]+=y,se[1][x]+=y,ad[x]+=y,sum[x]+=(LL)len[x]*y;}
inline void upd(int k,bool d)
{
    register int t=k<<1|cmp(fm[d][k<<1],fm[d][k<<1|1]);
    fm[d][k]=fm[d][t],fc[d][k]=fc[d][t];
    fm[d][k<<1]^fm[d][k<<1|1]?
    se[d][k]=cmp(fm[d][t^1],se[d][t])?se[d][t]:fm[d][t^1]
    :(fc[d][k]+=fc[d][k<<1|1],
    se[d][k]=se[d][k<<1|cmp(se[d][k<<1],se[d][k<<1|1])]);
}
void build(int k,int l,int r)
{
    len[k]=r-l+1,l^r?build(k<<1,l,mid),build(k<<1|1,mid+1,r),pu:(void)
    (rd(v),fm[0][k]=fm[1][k]=sum[k]=v,fc[0][k]=fc[1][k]=1,se[1][k]=-(se[0][k]=inf));
}
inline void mini(int k,int s,bool d)
{
    sum[k]+=(s-fm[d^1][k])*(LL)fc[d^1][k],fm[d^1][k]=s,
    cmp(s,fm[d][k])?cmp(se[d][k],s)?se[d][k]=s:0
    :(fm[0][k]=fm[1][k]=s,fc[0][k]=fc[1][k]=len[k],
    se[0][k]=inf,se[1][k]=-inf);
}
void mdf(int k,int l,int r,int d)
{
    if(ll>r||rr<l||d<2&&!cmp(fm[d^1][k],v))return;
    if(ll<=l&&rr>=r)
    {
        if(d>1)return add(k,v);
        else if(cmp(v,se[d^1][k]))
        return mini(k,v,d);
    }
    pd,mdf(k<<1,l,mid,d),mdf(k<<1|1,mid+1,r,d),pu;
}
int qry(int k,int l,int r,bool d)
{
    if(ll>r||rr<l)return d?-inf:inf;
    if(ll<=l&&rr>=r)return fm[d][k];
    pd;
    register int t1=qry(k<<1,l,mid,d),
    t2=qry(k<<1|1,mid+1,r,d);
    return cmp(t1,t2)?t2:t1;
}
LL qsum(int k,int l,int r)
{
    return ll>l||rr<r?ll>r||rr<l?0:(pd,qsum(k<<1,
    l,mid)+qsum(k<<1|1,mid+1,r)):sum[k];
}
int op;
int main()
{
    rd(n);
    build(1,1,n),rd(m);
    while(m--)rd(op),rd(ll),rd(rr),
    op<4?rd(v),op==1&&!v?(void)0:mdf(1,1,n,3-op):(void)
    (op<5?printf("%lld\n",qsum(1,1,n))
    :printf("%d\n",qry(1,1,n,6-op)));
}

猜你喜欢

转载自blog.csdn.net/Starria/article/details/79437057
今日推荐