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] 里大于 ...
随机推荐
- POJ 1088 滑雪 ( DFS+动态规划思想 )
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 79519 Accepted: 29581 Description ...
- 学习c编程的第二天
函数又叫方法,是实现某项功能或完成某项任务的代码块 #include<stdio.h>void show(){ printf("I like c language"); ...
- 纯属娱乐,对入门Android有一定的帮助
package android.m9; import android.app.Activity; import android.os.Bundle; import android.view.Men ...
- Service的两种启动方式
今天又写Service,提示覆写onBind(),想起Android好像是有个叫做Binder的IPC机制. Service里面有一个onBind(),一个onStartCommand(),两者都能启 ...
- POJ 3104 Contestants Division
Contestants Division Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10597 Accepted: ...
- 十五、事务(Transaction)
1.事务是什么? 2.示例 查询事务的隔离级别, 1>会话级(select @@tx_isolation或select @@session.tx_isolation) 2>全局级(sele ...
- codeforces 813C The Tag Game 树+dfs追击问题
C. The Tag Gametime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutpu ...
- oracle创建用户空间、导出、导入dmp备份文件方法
导入数据需要注意的事项 1.创建一个用户对应一个表空间. 2.创建的用户和表空间一定要与bmp文件的用户和表空间一致. 3.导入的命令是在CMD下输入的 不是在SQL plus输入的. 4.可以用PL ...
- SQL Server服务器连接配置
一.首先确保服务器能在本地打开数据库 如果碰到本地无法连接到数据库,首先要确认上图中两个服务是否开启 二.其次,要配置远端可连接的用户 如图,配置数据库[属性]中[安全性]为混合验证,勾中允许远程连接 ...
- LeetCode: 412 Fizz Buzz(easy)
题目: Write a program that outputs the string representation of numbers from 1 to n. But for multiples ...