bzoj4695: 最假女选手
题意
给出长为N(<=5e5)的序列,要求支持区间加、区间取min/max、区间求和、区间求min/max。
题解
我 好久好久以前 就想学这个科技…
的
区间取min/max时,对于被包含的区间,如果可以只更改min/max的值,那么直接修改,否则暴力dfs下去。
其他操作不变。
听说课件里那个单log的证明有锅?
照本宣科一发。势能函数定义为线段树里最值异于其父节点最值的节点个数。
以区间对v取min为例。
终止节点只有 和
第一种的兄弟节点一定是被访问过的非终止节点或第二种终止节点,所以这个我们不考虑。
第二种终止节点在取min后的max和父节点的max相等。
因此势能函数减少 ,对复杂度的贡献是 。
区间加涉及 个节点,因此势能函数最多增加 。
所以总复杂度是 。这么说起来,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)));
}