算导:

核算法

给每种操作一个摊还代价(是手工定义的),给数据结构中某些东西一个“信用”值(不是手动定义的,是被动产生的),摊还代价等于实际代价+信用变化量。

当实际代价小于摊还代价时,增加等于差额的信用;

当实际代价大于摊还代价时,减少等于差额的信用。

显然总摊还代价等于总实际代价+总信用变化量。

如果信用变化量始终>=0,那么总摊还代价给出总实际代价的一个上界;设法证明信用变化量始终>=0

势能法

对整个数据结构定义一个“势”函数$\Phi$

定义一个操作的摊还代价为实际代价加上势的变化量

那么摊还代价的总和,等于实际代价的总和,加上整个过程中势的变化量

如果“整个过程中势的变化量”始终大于等于0,那么摊还代价的总和,给出了实际代价总和的一个上界

在实际代价难以计算的情况下,可以设计合适的势函数,使得每一次操作的摊还代价容易计算

(其实就是把“信用”的定义换到整个数据结构上来)


吉司机线段树:

https://codeforces.com/blog/entry/57319

实际上也不是就一定要用上面的方法..

里面好像是先分析对势函数的修改,得到势函数增长的上限,而对于extranode,访问一个节点就会减少1的势函数,势函数又始终>=0,因此得到extranode访问次数的上限;其余的访问次数的证明套用普通线段树区间操作即可


https://www.lydsy.com/JudgeOnline/problem.php?id=4695

每个节点维护区间最小值,次小值,最小值出现次数,最大值,次大值,最大值出现次数,区间和

(维护最小/大值出现次数,是为了方便在打上取min/取max标记同时,计算出对区间和的修改)

维护取min标记,取max标记,加法标记(加法标记优先级最低,前面两个要手动定义一个优先级)

然后用那篇cf帖子里面的方法做区间取min和区间取max操作,用普通线段树的方法做区间加法操作

pushdown的时候按照手工定义的三个操作的优先级进行

给节点加上标记时,细节很多,注意几个:

先考虑对数值的影响,再考虑对之前标记的影响

对数值的影响:

加法操作:就是最(次)大(小)值都要加上这个数,也要对应修改区间和;

取min/max操作:如果区间只有一种值或两种值,显然需要特判(就是打取min标记也要修改最小/次小值,打取max标记也要修改最大/次大值);打取min标记肯定要修改最大/次大值,打取max标记肯定要修改最小/次小值,肯定要对应修改区间和(具体方法:充分发扬人类智慧???就是说乱搞一下,能搞的)

对之前标记的影响:举例:设优先级:取min标记>取max标记>加法标记

要打取min/max标记了(设与x取min/max),如果之前有过加法标记(设加y),为了按照这个优先级的顺序做操作能得出正确结果,实际应该打上的标记是x-y;如果之前有过同样类型的标记,显然要对应取一下min/max

要打取min标记了(与x取min),如果之前有过取max标记(与y取max),且x<y,那么数就是先变到(y)再变到小(x),要让这个取max标记也变为x

pushup的细节也很多。。

upd:以下所有代码tag_condition都要变成(l==r)||(原内容),pushdown都要加一句if(l==r)return;虽然因为某些原因没有出锅,但是最好还是加上以防万一(其实是另一个题出了锅)

 #pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int a[];
namespace S
{
const int mininf=-0x7fffffff;
const int maxinf=0x7fffffff;
#define N 1050000
#define lc (num<<1)
#define rc (num<<1|1)
struct I
{
int min1,min2,min1cnt;
int max1,max2,max1cnt;
ll sum;
};
I operator+(const I &a,const I &b)
{
I ans;ans.sum=a.sum+b.sum;
if(a.min1<b.min1)
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt;
ans.min2=min(a.min2,b.min1);
}
else if(a.min1>b.min1)
{
ans.min1=b.min1;ans.min1cnt=b.min1cnt;
ans.min2=min(b.min2,a.min1);
}
else
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt+b.min1cnt;
ans.min2=min(a.min2,b.min2);
}
if(a.max1>b.max1)
{
ans.max1=a.max1;ans.max1cnt=a.max1cnt;
ans.max2=max(a.max2,b.max1);
}
else if(a.max1<b.max1)
{
ans.max1=b.max1;ans.max1cnt=b.max1cnt;
ans.max2=max(b.max2,a.max1);
}
else
{
ans.max1=a.max1;ans.max1cnt=a.max1cnt+b.max1cnt;
ans.max2=max(a.max2,b.max2);
}
return ans;
}
I d[N];
int minv[N],maxv[N],addv[N];
bool setmin[N],setmax[N];
//规定标记:先取min,再取max,再加
void putMax(int x,int l,int r,int num)
//要求min1<x<min2
//先考虑对数值的影响,再考虑对标记的影响
{
if(d[num].min1>=x) return;
//assert(x<d[num].min2);
//if(setmax[num]&&x-addv[num]<maxv[num]) return;
if(d[num].min2==maxinf) d[num].max1=x;
else if(d[num].min1==d[num].max2) d[num].max2=x;
d[num].sum+=ll(d[num].min1cnt)*(x-d[num].min1);
d[num].min1=x;
if(!setmax[num]) setmax[num]=,maxv[num]=x-addv[num];
else maxv[num]=max(maxv[num],x-addv[num]);
}
void putMin(int x,int l,int r,int num)
{
if(d[num].max1<=x) return;
//assert(x>d[num].max2);
//if(setmin[num]&&x-addv[num]>minv[num]) return;
if(d[num].max2==mininf) d[num].min1=x;
else if(d[num].max1==d[num].min2) d[num].min2=x;
d[num].sum-=ll(d[num].max1cnt)*(d[num].max1-x);
d[num].max1=x;
/*
if(d[num].max2==mininf)
{
if(setmax[num])
{
if(maxv[num]>x)
{
d[num].min1=x;
setmax[num]=0;
}
}
else
d[num].min1=x;
}
else if(d[num].max1==d[num].min2)
{
if(setmax[num])
{
if(maxv[num]<x) d[num].min2=x;
else
{
d[num].min1=d[num].max1=x;
d[num].min2=maxinf;d[num].max2=mininf;
d[num].min1cnt=d[num].max1cnt=r-l+1;
setmax[num]=0;
}
}
else
d[num].min2=x;
}
*/
if(setmax[num]&&maxv[num]>x-addv[num]) maxv[num]=x-addv[num];
if(!setmin[num]) setmin[num]=,minv[num]=x-addv[num];
else minv[num]=min(minv[num],x-addv[num]);
}
void doAdd(int x,int l,int r,int num)
{
d[num].sum+=ll(x)*(r-l+);
d[num].min1+=x;d[num].max1+=x;
if(d[num].min2!=maxinf) d[num].min2+=x;
if(d[num].max2!=mininf) d[num].max2+=x;
addv[num]+=x;
}
void pd(int l,int r,int num)
{
int mid=l+((r-l)>>);
if(setmin[num])
{
putMin(minv[num],l,mid,lc);
putMin(minv[num],mid+,r,rc);
setmin[num]=;
}
if(setmax[num])
{
putMax(maxv[num],l,mid,lc);
putMax(maxv[num],mid+,r,rc);
setmax[num]=;
}
if(addv[num])
{
doAdd(addv[num],l,mid,lc);
doAdd(addv[num],mid+,r,rc);
addv[num]=;
}
}
void build(int l,int r,int num)
{
if(l==r)
{
d[num].max1=d[num].min1=d[num].sum=a[l];
d[num].max2=mininf;d[num].min2=maxinf;
d[num].max1cnt=d[num].min1cnt=;
return;
}
int mid=l+((r-l)>>);
build(l,mid,lc);build(mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cmin(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)||(d[num].max1<=x)) return;
if((L<=l&&r<=R)&&(d[num].max2<x&&x<d[num].max1))
{
putMin(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cmin(L,R,x,l,mid,lc);
cmin(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cmax(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)||(d[num].min1>=x)) return;
if((L<=l&&r<=R)&&(d[num].min2>x&&x>d[num].min1))
{
putMax(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cmax(L,R,x,l,mid,lc);
cmax(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cadd(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)) return;
if((L<=l&&r<=R))
{
doAdd(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cadd(L,R,x,l,mid,lc);
cadd(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
I gett(int L,int R,int l,int r,int num)
{
if(L<=l&&r<=R) return d[num];
pd(l,r,num);
int mid=l+((r-l)>>);
if(L<=mid&&mid<R) return gett(L,R,l,mid,lc)+gett(L,R,mid+,r,rc);
else if(L<=mid) return gett(L,R,l,mid,lc);
else if(mid<R) return gett(L,R,mid+,r,rc);
else exit(-);
}
#undef lc
#undef rc
}
int n,m;
int main()
{
int i,idx,l,r,x;
//freopen("/tmp/4695/10.in","r",stdin);
//freopen("/tmp/4695/10.ans","w",stdout);
scanf("%d",&n);
for(i=;i<=n;i++) scanf("%d",&a[i]);
S::build(,n,);
scanf("%d",&m);
for(i=;i<=m;i++)
{
scanf("%d",&idx);
switch(idx)
{
case :
scanf("%d%d%d",&l,&r,&x);
S::cadd(l,r,x,,n,);
break;
case :
scanf("%d%d%d",&l,&r,&x);
S::cmax(l,r,x,,n,);
break;
case :
scanf("%d%d%d",&l,&r,&x);
S::cmin(l,r,x,,n,);
break;
case :
scanf("%d%d",&l,&r);
printf("%lld\n",S::gett(l,r,,n,).sum);
break;
case :
scanf("%d%d",&l,&r);
printf("%d\n",S::gett(l,r,,n,).max1);
break;
case :
scanf("%d%d",&l,&r);
printf("%d\n",S::gett(l,r,,n,).min1);
break;
}
}
return ;
}

https://vjudge.net/problem/HDU-5306

 #pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int a[];
namespace S
{
const int mininf=-0x7fffffff;
const int maxinf=0x7fffffff;
#define N 2100000
#define lc (num<<1)
#define rc (num<<1|1)
struct I
{
int min1,min2,min1cnt;
int max1,max2,max1cnt;
ll sum;
};
I operator+(const I &a,const I &b)
{
I ans;ans.sum=a.sum+b.sum;
if(a.min1<b.min1)
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt;
ans.min2=min(a.min2,b.min1);
}
else if(a.min1>b.min1)
{
ans.min1=b.min1;ans.min1cnt=b.min1cnt;
ans.min2=min(b.min2,a.min1);
}
else
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt+b.min1cnt;
ans.min2=min(a.min2,b.min2);
}
if(a.max1>b.max1)
{
ans.max1=a.max1;ans.max1cnt=a.max1cnt;
ans.max2=max(a.max2,b.max1);
}
else if(a.max1<b.max1)
{
ans.max1=b.max1;ans.max1cnt=b.max1cnt;
ans.max2=max(b.max2,a.max1);
}
else
{
ans.max1=a.max1;ans.max1cnt=a.max1cnt+b.max1cnt;
ans.max2=max(a.max2,b.max2);
}
return ans;
}
I d[N];
int minv[N],maxv[N],addv[N];
bool setmin[N],setmax[N];
//规定标记:先取min,再取max,再加
void putMax(int x,int l,int r,int num)
//要求min1<x<min2
//先考虑对数值的影响,再考虑对标记的影响
{
if(d[num].min1>=x) return;
//assert(x<d[num].min2);
//if(setmax[num]&&x-addv[num]<maxv[num]) return;
if(d[num].min2==maxinf) d[num].max1=x;
else if(d[num].min1==d[num].max2) d[num].max2=x;
d[num].sum+=ll(d[num].min1cnt)*(x-d[num].min1);
d[num].min1=x;
if(!setmax[num]) setmax[num]=,maxv[num]=x-addv[num];
else maxv[num]=max(maxv[num],x-addv[num]);
}
void putMin(int x,int l,int r,int num)
{
if(d[num].max1<=x) return;
//assert(x>d[num].max2);
//if(setmin[num]&&x-addv[num]>minv[num]) return;
if(d[num].max2==mininf) d[num].min1=x;
else if(d[num].max1==d[num].min2) d[num].min2=x;
d[num].sum-=ll(d[num].max1cnt)*(d[num].max1-x);
d[num].max1=x;
/*
if(d[num].max2==mininf)
{
if(setmax[num])
{
if(maxv[num]>x)
{
d[num].min1=x;
setmax[num]=0;
}
}
else
d[num].min1=x;
}
else if(d[num].max1==d[num].min2)
{
if(setmax[num])
{
if(maxv[num]<x) d[num].min2=x;
else
{
d[num].min1=d[num].max1=x;
d[num].min2=maxinf;d[num].max2=mininf;
d[num].min1cnt=d[num].max1cnt=r-l+1;
setmax[num]=0;
}
}
else
d[num].min2=x;
}
*/
if(setmax[num]&&maxv[num]>x-addv[num]) maxv[num]=x-addv[num];
if(!setmin[num]) setmin[num]=,minv[num]=x-addv[num];
else minv[num]=min(minv[num],x-addv[num]);
}
void doAdd(int x,int l,int r,int num)
{
d[num].sum+=ll(x)*(r-l+);
d[num].min1+=x;d[num].max1+=x;
if(d[num].min2!=maxinf) d[num].min2+=x;
if(d[num].max2!=mininf) d[num].max2+=x;
addv[num]+=x;
}
void pd(int l,int r,int num)
{
int mid=l+((r-l)>>);
if(setmin[num])
{
putMin(minv[num],l,mid,lc);
putMin(minv[num],mid+,r,rc);
setmin[num]=;
}
if(setmax[num])
{
putMax(maxv[num],l,mid,lc);
putMax(maxv[num],mid+,r,rc);
setmax[num]=;
}
if(addv[num])
{
doAdd(addv[num],l,mid,lc);
doAdd(addv[num],mid+,r,rc);
addv[num]=;
}
}
void build(int l,int r,int num)
{
setmin[num]=setmax[num]=;addv[num]=;
if(l==r)
{
d[num].max1=d[num].min1=d[num].sum=a[l];
d[num].max2=mininf;d[num].min2=maxinf;
d[num].max1cnt=d[num].min1cnt=;
return;
}
int mid=l+((r-l)>>);
build(l,mid,lc);build(mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cmin(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)||(d[num].max1<=x)) return;
if((L<=l&&r<=R)&&(d[num].max2<x&&x<d[num].max1))
{
putMin(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cmin(L,R,x,l,mid,lc);
cmin(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cmax(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)||(d[num].min1>=x)) return;
if((L<=l&&r<=R)&&(d[num].min2>x&&x>d[num].min1))
{
putMax(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cmax(L,R,x,l,mid,lc);
cmax(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cadd(int L,int R,int x,int l,int r,int num)
{
if((r<L||R<l)) return;
if((L<=l&&r<=R))
{
doAdd(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cadd(L,R,x,l,mid,lc);
cadd(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
I gett(int L,int R,int l,int r,int num)
{
if(L<=l&&r<=R) return d[num];
pd(l,r,num);
int mid=l+((r-l)>>);
if(L<=mid&&mid<R) return gett(L,R,l,mid,lc)+gett(L,R,mid+,r,rc);
else if(L<=mid) return gett(L,R,l,mid,lc);
else if(mid<R) return gett(L,R,mid+,r,rc);
else exit(-);
}
#undef lc
#undef rc
}
int n,m;
int main()
{
int i,idx,l,r,x,T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(i=;i<=n;i++) scanf("%d",&a[i]);
S::build(,n,);
for(i=;i<=m;i++)
{
scanf("%d",&idx);
switch(idx)
{
case :
scanf("%d%d%d",&l,&r,&x);
S::cmin(l,r,x,,n,);
break;
case :
scanf("%d%d",&l,&r);
printf("%d\n",S::gett(l,r,,n,).max1);
break;
case :
scanf("%d%d",&l,&r);
printf("%lld\n",S::gett(l,r,,n,).sum);
break;
}
}}
return ;
}

小B的序列

http://210.33.19.103/contest/888/problem/2

啧,貌似是原题https://www.lydsy.com/JudgeOnline/problem.php?id=5312

题意:区间取and,区间取or,区间最大值

对每一(二进制)位搞一个以上类型的线段树,那么修改操作相当于,对于某些位的线段树,区间对0取min或对1取max(对x取and就是x中为0的位对应线段树区间对0取min,对x取or就是x中为1的位对应线段树区间对1取max)

当然这样子直接搞不能维护最大值,可以把所有位绑在一起,只建一个线段树,就可以维护了

这样的话,当当前节点区间[l,r]被目标区间[L,R]完全包含时,如果存在一些操作位在这个区间有0也有1,那么必须要向下dfs;如果所有操作位在这个区间要么全0要么全1,那么就是说要么满足break_condition,要么满足tag_condition,但是这个不用细分,直接puttag就行了(可以发现效果不变的)

错误记录:81,97行没有搞清问题本质,强行区分break和tag,于是复杂度错掉,T飞

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cassert>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int a[];
//int num1;
namespace S
{
const int N=;
const int all1=(<<)-;
#define lc (num<<1)
#define rc (num<<1|1)
//#define flip(x) (all1&(~(x)))
#define flip(x) (all1^(x))
int andv[N],orv[N],isall0[N],isall1[N],maxn[N];
//先and,再or
void doOr(int x,int l,int r,int num)
{
//if((isall1[num]&x)==x) return;
maxn[num]|=x;
isall0[num]&=flip(x);isall1[num]|=x;
orv[num]|=x;
}
void doAnd(int x,int l,int r,int num)
{
//if((isall0[num]&flip(x))==flip(x)) return;
maxn[num]&=x;
isall1[num]&=x;isall0[num]|=flip(x);
andv[num]&=x;orv[num]&=x;
}
void pd(int l,int r,int num)
{
if(l==r) return;
int mid=l+((r-l)>>);
if(andv[num]!=all1)
{
doAnd(andv[num],l,mid,lc);
doAnd(andv[num],mid+,r,rc);
andv[num]=all1;
}
if(orv[num])
{
doOr(orv[num],l,mid,lc);
doOr(orv[num],mid+,r,rc);
orv[num]=;
}
}
void upd(int l,int r,int num)
{
isall0[num]=isall0[lc]&isall0[rc];
isall1[num]=isall1[lc]&isall1[rc];
maxn[num]=max(maxn[lc],maxn[rc]);
}
void build(int l,int r,int num)
{
andv[num]=all1;orv[num]=;
if(l==r)
{
isall0[num]=flip(a[l]);
isall1[num]=a[l];
maxn[num]=a[l];
return;
}
int mid=l+((r-l)>>);
build(l,mid,lc);build(mid+,r,rc);
upd(l,r,num);
}
void cor(int L,int R,int x,int l,int r,int num)
{//num1++;
if((r<L||R<l)) return;
//printf("or%d %d %d\n",l,r,num);
if(l==r||((L<=l&&r<=R)&&(((isall0[num]&x)|(isall1[num]&x))==x)))
{
doOr(x,l,r,num);
return;
}
//if(l==r) return;
pd(l,r,num);
int mid=l+((r-l)>>);
cor(L,R,x,l,mid,lc);
cor(L,R,x,mid+,r,rc);
upd(l,r,num);
}
void cand(int L,int R,int x,int l,int r,int num)
{//num1++;
if((r<L||R<l)) return;
//printf("and%d %d %d\n",l,r,num);
if(l==r||((L<=l&&r<=R)&&(((isall1[num]&flip(x))|(isall0[num]&flip(x)))==flip(x))))
{
doAnd(x,l,r,num);
return;
}
//if(l==r) return;
pd(l,r,num);
int mid=l+((r-l)>>);
cand(L,R,x,l,mid,lc);
cand(L,R,x,mid+,r,rc);
upd(l,r,num);
}
int gmax(int L,int R,int l,int r,int num)
{
if(L<=l&&r<=R) return maxn[num];
pd(l,r,num);
int mid=l+((r-l)>>),ans=-;
if(L<=mid) ans=max(ans,gmax(L,R,l,mid,lc));
if(mid<R) ans=max(ans,gmax(L,R,mid+,r,rc));
return ans;
}
#undef lc
#undef rc
}
int n,q;
int main()
{
int i,idx,l,r,x;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++) scanf("%d",&a[i]);
S::build(,n,);
while(q--)
{
//int t=num1;
scanf("%d",&idx);
switch(idx)
{
case :
scanf("%d%d%d",&l,&r,&x);
S::cand(l,r,x,,n,);
break;
case :
scanf("%d%d%d",&l,&r,&x);
S::cor(l,r,x,,n,);
break;
case :
scanf("%d%d",&l,&r);
S::gmax(l,r,,n,);
printf("%d\n",S::gmax(l,r,,n,));
}
//if(num1-t>100000) printf("%d\n",num1-t);
//if(q%1000==0)printf("test%d\n",num1);
}
return ;
}

https://www.lydsy.com/JudgeOnline/problem.php?id=4355

接着改板子。。。

错误记录:17行最大值不够大

 #pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
ll a[];
namespace S
{
const ll maxinf=0x7fffffffffffffff;
#define N 1050000
#define lc (num<<1)
#define rc (num<<1|1)
struct I
{
ll min1,min2,min1cnt;
};
I operator+(const I &a,const I &b)
{
I ans;
if(a.min1<b.min1)
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt;
ans.min2=min(a.min2,b.min1);
}
else if(a.min1>b.min1)
{
ans.min1=b.min1;ans.min1cnt=b.min1cnt;
ans.min2=min(b.min2,a.min1);
}
else
{
ans.min1=a.min1;ans.min1cnt=a.min1cnt+b.min1cnt;
ans.min2=min(a.min2,b.min2);
}
return ans;
}
I d[N];
ll maxv[N],addv[N],setv[N];
bool setmax[N],set[N];
//规定标记:先赋值,再取max,再加
void putMax(ll x,int l,int r,int num)
//要求min1<x<min2
//先考虑对数值的影响,再考虑对标记的影响
{
if(d[num].min1>=x) return;
d[num].min1=x;
if(!setmax[num]) setmax[num]=,maxv[num]=x-addv[num];
else maxv[num]=max(maxv[num],x-addv[num]);
}
void doSet(ll x,int l,int r,int num)
{
d[num].min1=x;d[num].min2=maxinf;d[num].min1cnt=r-l+;
setmax[num]=;addv[num]=;
set[num]=;setv[num]=x;
}
void doAdd(ll x,int l,int r,int num)
{
d[num].min1+=x;
if(d[num].min2!=maxinf) d[num].min2+=x;
addv[num]+=x;
}
void pd(int l,int r,int num)
{
int mid=l+((r-l)>>);
if(set[num])
{
doSet(setv[num],l,mid,lc);
doSet(setv[num],mid+,r,rc);
set[num]=;
}
if(setmax[num])
{
putMax(maxv[num],l,mid,lc);
putMax(maxv[num],mid+,r,rc);
setmax[num]=;
}
if(addv[num])
{
doAdd(addv[num],l,mid,lc);
doAdd(addv[num],mid+,r,rc);
addv[num]=;
}
}
void build(int l,int r,int num)
{
if(l==r)
{
d[num].min1=a[l];
d[num].min2=maxinf;
d[num].min1cnt=;
return;
}
int mid=l+((r-l)>>);
build(l,mid,lc);build(mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cmax(int L,int R,ll x,int l,int r,int num)
{
if((r<L||R<l)||(d[num].min1>=x)) return;
if((L<=l&&r<=R)&&(d[num].min2>x&&x>d[num].min1))
{
putMax(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cmax(L,R,x,l,mid,lc);
cmax(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cadd(int L,int R,ll x,int l,int r,int num)
{
if((r<L||R<l)) return;
if((L<=l&&r<=R))
{
doAdd(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cadd(L,R,x,l,mid,lc);
cadd(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
void cset(int L,int R,ll x,int l,int r,int num)
{
if((r<L||R<l)) return;
if((L<=l&&r<=R))
{
doSet(x,l,r,num);
return;
}
pd(l,r,num);
int mid=l+((r-l)>>);
cset(L,R,x,l,mid,lc);
cset(L,R,x,mid+,r,rc);
d[num]=d[lc]+d[rc];
}
I gett(int L,int R,int l,int r,int num)
{
if(L<=l&&r<=R) return d[num];
pd(l,r,num);
int mid=l+((r-l)>>);
if(L<=mid&&mid<R) return gett(L,R,l,mid,lc)+gett(L,R,mid+,r,rc);
else if(L<=mid) return gett(L,R,l,mid,lc);
else if(mid<R) return gett(L,R,mid+,r,rc);
else exit(-);
}
#undef lc
#undef rc
}
int n,m;
int main()
{
int i,idx,l,r;ll x;S::I ttt;
//freopen("/tmp/4355/11.in","r",stdin);
//freopen("/tmp/4355/11.ans","w",stdout);
scanf("%d%d",&n,&m);
for(i=;i<=n;i++) scanf("%lld",&a[i]);
S::build(,n,);
for(i=;i<=m;i++)
{
scanf("%d",&idx);
switch(idx)
{
case :
scanf("%d%d%lld",&l,&r,&x);
S::cset(l,r,x,,n,);
break;
case :
scanf("%d%d%lld",&l,&r,&x);
S::cadd(l,r,x,,n,);
S::cmax(l,r,,,n,);
break;
case :
scanf("%d%d",&l,&r);
ttt=S::gett(l,r,,n,);
printf("%lld\n",ttt.min1==?ttt.min1cnt:);
}
}
return ;
}

bzoj 4695: 最假女选手 && Gorgeous Sequence HDU - 5306 && (bzoj5312 冒险 || 小B的序列) && bzoj4355: Play with sequence的更多相关文章

  1. bzoj 4695 最假女选手 吉利线段树

    最假女选手 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 480  Solved: 118[Submit][Status][Discuss] Desc ...

  2. BZOJ.4695.最假女选手(线段树 Segment tree Beats!)

    题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...

  3. bzoj 4695: 最假女选手

    ……一道丧病线段树膜板题…… 被常数卡的死去活来……QAQ 学到了些奇技淫巧:把取min标记 和 区间最小值 合并 可以快很多…… #include <bits/stdc++.h> #de ...

  4. BZOJ 4695 最假女选手 线段树

    题意: 给定一个长度为 N序列,编号从1 到 N.要求支持下面几种操作: 1.给一个区间[L,R] 加上一个数x  2.把一个区间[L,R] 里小于x 的数变成x  3.把一个区间[L,R] 里大于x ...

  5. BZOJ4695 最假女选手(势能线段树)

    BZOJ题目传送门 终于体会到初步掌握势能分析思想的重要性了. 一开始看题,感觉套路还是很一般啊qwq.直接在线段树上维护最大值和最小值,每次递归更新的时候,如果不能完全覆盖就暴力递归下去.挺好写的欸 ...

  6. bzoj4695 最假女选手

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695 [题解] SegmentTree beats!(见jiry_2论文/营员交流) 考虑只 ...

  7. BZOJ4695:最假女选手

    浅谈区间最值操作和历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html 题目传送门:https://lydsy.com/JudgeOnline/pr ...

  8. 2018.07.27 bzoj4695: 最假女选手(线段树)

    传送门 线段树好题 支持区间加,区间取min" role="presentation" style="position: relative;"> ...

  9. 【bzoj4695】最假女选手 线段树区间最值操作

    题目描述 给定一个长度为 N 序列,编号从 1 到 N .要求支持下面几种操作:1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] 里大于 ...

随机推荐

  1. Codeforces Round #379 (Div. 2) D. Anton and Chess —— 基础题

    题目链接:http://codeforces.com/contest/734/problem/D D. Anton and Chess time limit per test 4 seconds me ...

  2. git rev-list 和 git rev-parse

    git-rev-list - Lists commit objects in reverse chronological order https://git-scm.com/docs/git-rev- ...

  3. PYTHON 爬虫笔记二:Urllib库基本使用

    知识点一:urllib的详解及基本使用方法 一.基本介绍 urllib是python的一个获取url(Uniform Resource Locators,统一资源定址器)了,我们可以利用它来抓取远程的 ...

  4. 使用ffmpeg添加logo

    1 网上搜出的一些ffmpeg添加logo的命令都不成功,调查了官方手册后以下这种用法成功: ffmpeg -y -i input.mp4 -vf "movie=logo.png [logo ...

  5. static静态数据的初始化

    package com.demo.book; public class StaticInitialization { static Table table = new Table(); static ...

  6. hdu-4990 Reading comprehension(快速幂+乘法逆元)

    题目链接: Reading comprehension Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K ( ...

  7. codeforces 652C C. Foe Pairs(尺取法+线段树查询一个区间覆盖线段)

    题目链接: C. Foe Pairs time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  8. 【C】论‘\r’和'\n'的纯粹性

  9. java推荐书籍及下载

    前言 一直有这么个想法,列一下我个人认为在学习和使用Java过程中可以推荐一读的书籍,给初学者或者想深入的朋友一些建议,帮助成长.推荐的的都是我自己读过,也会推荐一些朋友读过并且口碑不错的书籍.以下的 ...

  10. SQL SERVER2008 打开脚本总是报“未能完成操作,存储空间不足”

    使用用SQLCMD命令行. 1.快捷键:win+R 2.输入cmd​,确定 3.输入命令:sqlcmd -S <数据库服务器名称> -i C:\<脚本文件路径>.sql 如图所 ...