bzoj 4695: 最假女选手 && Gorgeous Sequence HDU - 5306 && (bzoj5312 冒险 || 小B的序列) && bzoj4355: Play with sequence
算导:
核算法
给每种操作一个摊还代价(是手工定义的),给数据结构中某些东西一个“信用”值(不是手动定义的,是被动产生的),摊还代价等于实际代价+信用变化量。
当实际代价小于摊还代价时,增加等于差额的信用;
当实际代价大于摊还代价时,减少等于差额的信用。
显然总摊还代价等于总实际代价+总信用变化量。
如果信用变化量始终>=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的更多相关文章
- bzoj 4695 最假女选手 吉利线段树
最假女选手 Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 480 Solved: 118[Submit][Status][Discuss] Desc ...
- BZOJ.4695.最假女选手(线段树 Segment tree Beats!)
题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...
- bzoj 4695: 最假女选手
……一道丧病线段树膜板题…… 被常数卡的死去活来……QAQ 学到了些奇技淫巧:把取min标记 和 区间最小值 合并 可以快很多…… #include <bits/stdc++.h> #de ...
- BZOJ 4695 最假女选手 线段树
题意: 给定一个长度为 N序列,编号从1 到 N.要求支持下面几种操作: 1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] 里大于x ...
- BZOJ4695 最假女选手(势能线段树)
BZOJ题目传送门 终于体会到初步掌握势能分析思想的重要性了. 一开始看题,感觉套路还是很一般啊qwq.直接在线段树上维护最大值和最小值,每次递归更新的时候,如果不能完全覆盖就暴力递归下去.挺好写的欸 ...
- bzoj4695 最假女选手
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695 [题解] SegmentTree beats!(见jiry_2论文/营员交流) 考虑只 ...
- BZOJ4695:最假女选手
浅谈区间最值操作和历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html 题目传送门:https://lydsy.com/JudgeOnline/pr ...
- 2018.07.27 bzoj4695: 最假女选手(线段树)
传送门 线段树好题 支持区间加,区间取min" role="presentation" style="position: relative;"> ...
- 【bzoj4695】最假女选手 线段树区间最值操作
题目描述 给定一个长度为 N 序列,编号从 1 到 N .要求支持下面几种操作:1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] 里大于 ...
随机推荐
- Photoshop颜色通道实例
PHOTOSHOP学到这会儿,我们不得不来学学枯燥乏味的颜色理论了,因为如果再不学,就难以学下去了.眼下我们就遇到了难点:颜色通道.前面在初识通道的时候,我已经说过:当你打开一张照片(RGB模式)的时 ...
- vue路由总结
vue-router, vue自带的路由,下面是一些简单的操作说明: 一.安装 1.cnpm install vue-router --save 命令进行安装 2.在main.js或者使用vue-r ...
- 理解HTML解析过程
浏览器解析html的过程是:接受网络数据->将二进制码变成字符->将字符变为unicode code points.->tokenizer ->tree constructor ...
- Android图片加载神器之Fresco, 基于各种使用场景的讲解
Fresco是Facebook开源Android平台上一个强大的图片加载库,也是迄今为止Android平台上最强大的图片加载库. 优点:相对于其他开源的第三方图片加载库,Fresco拥有更好的内存管理 ...
- 洛谷【P839】【NOI导刊】——数页码
题面 一道找规律好题... 首先,我们肯定只能一位一位的统计答案,考虑从高位向低位统计,显然这样要方便的多. 对于第i位,我们统计从$a[i+1]*10^i+0$到$a[i+1]*10^i+a[i]* ...
- python之yield和Generator
首先我们从一个小程序导入,各定一个list,找出其中的素数,我们会这样写 import math def is_Prims(number): if number == 2: return True / ...
- 小trick之mklink
因为要看很多论文就下载安装了zotero,又因为文献库的文件夹在安装目录太深,找起来太麻烦,再加上是软件本身的安装目录,因此把论文都下载在默认文件中总会天然地产生不安全感,万一误删软件怎么办.所以在文 ...
- JDBCTool
新建 *.properties属性文件,内容如下: driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/dbName userna ...
- ubuntu bcompare 安装
Terminal Install wget http://www.scootersoftware.com/bcompare-4.2.8.23479_amd64.deb sudo apt-get upd ...
- cf 424
Office Keys 首先显然有随人位置的递增,钥匙的位置也要递增,这样考虑两张做法: 1.$f(i,j)$ 表示前i个人,钥匙到第j个最少用的最大时间,然后$O(nK)$ dp 2.二分时间,对于 ...