HDU5828(线段树好题,区间加,区间求根号,吉老师在51nod直播讲过这道题,相应的还有区间取模)
2017-07-22 22:21
253 查看
题解:区间加,区间和不用说。重点在区间取模,首先,就算一个很大的n,几次根号之后就会很小。
我们可以思考一下,如果一个区间内的极差>1的时候,不断地进行整体加某个值然后开方,是没办法保持住这样的序列的(相邻两个极差都>1)。只有整个区间内的极差<=1的时候,才能起到这种效果。所以我们就在线段树上再增加一些信息。就是最大值和最小值,最大值的个数,最小值的个数。这样的话,如果区间内的极差==1的时候,我们也能直接对整段进行操作。就能处理前面的这种样例了。
区间的极差==1的时候。那么这种情况开方以后有两种情况。1:整个区间相等了。2:整个区间的极差还是1。
对于第一种情况。我们只要加一个cover标记,加一个区间覆盖的标记就可以解决了。
对于第二种情况,相当于,区间减去了一个相等的值,修改一下区间增加的标记就可以了。然后在pushdown的时候增加一下cover的情况。
证明:
假设某一段区间的最大值x,和最小值y.
如果极差>1,那么这个极差经过很少的次数开根号, 其中的极差也会变得越来越小,
用公式来表达 假设当前这段区间要+d,然后再开根号.
必然有这样的式子
’
我们可以思考一下,如果一个区间内的极差>1的时候,不断地进行整体加某个值然后开方,是没办法保持住这样的序列的(相邻两个极差都>1)。只有整个区间内的极差<=1的时候,才能起到这种效果。所以我们就在线段树上再增加一些信息。就是最大值和最小值,最大值的个数,最小值的个数。这样的话,如果区间内的极差==1的时候,我们也能直接对整段进行操作。就能处理前面的这种样例了。
区间的极差==1的时候。那么这种情况开方以后有两种情况。1:整个区间相等了。2:整个区间的极差还是1。
对于第一种情况。我们只要加一个cover标记,加一个区间覆盖的标记就可以解决了。
对于第二种情况,相当于,区间减去了一个相等的值,修改一下区间增加的标记就可以了。然后在pushdown的时候增加一下cover的情况。
证明:
假设某一段区间的最大值x,和最小值y.
如果极差>1,那么这个极差经过很少的次数开根号, 其中的极差也会变得越来越小,
用公式来表达 假设当前这段区间要+d,然后再开根号.
必然有这样的式子
⌊x+d−−−−−√⌋−⌊y+d−−−−√⌋<=⌊x√⌋−⌊y√⌋
’#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define Mn 100010 #define Mm 2000005 #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; ll a[Mn]; ll sum[Mn*4]; ll maxx[Mn*4],minn[Mn*4]; ll maxNum[Mn*4],minNum[Mn*4]; ll all[Mn*4]; ll lazy[Mn*4]; void pushUp(int u) { sum[u]=sum[ul]+sum[ur]; maxx[u]=max(maxx[ul],maxx[ur]); minn[u]=min(minn[ul],minn[ur]); maxNum[u]=minNum[u]=0; if(maxx[u]==maxx[ul]) maxNum[u]+=maxNum[ul]; if(maxx[u]==maxx[ur]) maxNum[u]+=maxNum[ur]; if(minn[u]==minn[ul]) minNum[u]+=minNum[ul]; if(minn[u]==minn[ur]) minNum[u]+=minNum[ur]; } void pushDown(int u,int l,int r) { if(all[u]) { int mid=(l+r)>>1; all[ul]=all[ur]=all[u]; sum[ul]=all[u]*(mid-l+1); sum[ur]=all[u]*(r-mid); maxx[ul]=maxx[ur]=minn[ul]=minn[ur]=all[u]; maxNum[ul]=minNum[ul]=mid-l+1; maxNum[ur]=minNum[ur]=r-mid; lazy[ul]=lazy[ur]=0; all[u]=0; } if(lazy[u]) { int mid=(l+r)>>1; lazy[ul]+=lazy[u];lazy[ur]+=lazy[u]; sum[ul]+=lazy[u]*(mid-l+1); sum[ur]+=lazy[u]*(r-mid); maxx[ul]+=lazy[u];minn[ul]+=lazy[u]; maxx[ur]+=lazy[u];minn[ur]+=lazy[u]; lazy[u]=0; } } void build(int l,int r,int u) { all[u]=lazy[u]=maxx[u]=minn[u]=sum[u]=0; if(l==r) { maxx[u]=minn[u]=sum[u]=a[l]; maxNum[u]=minNum[u]=1; return ; } int mid=(l+r)>>1; build(l,mid,ul); build(mid+1,r,ur); pushUp(u); } int s,t; void add(int l,int r,int u,ll x) { if(s<=l&&t>=r) { sum[u]+=x*(r-l+1); minn[u]+=x; maxx[u]+=x; lazy[u]+=x; return ; } pushDown(u,l,r); int mid=(l+r)>>1; if(t<=mid) add(l,mid,ul,x); else if(s>mid) add(mid+1,r,ur,x); else{add(l,mid,ul,x);add(mid+1,r,ur,x);} pushUp(u); } void Sqrt(int l,int r,int u) { if(s<=l&&t>=r&&(maxx[u]-minn[u]<=1)) { if(maxx[u]==1) return ; ll x=maxx[u]; if(maxx[u]==minn[u]) { minn[u]=maxx[u]=floor(sqrt(x)); lazy[u]+=maxx[u]-x; sum[u]=maxx[u]*(r-l+1); return ; } else if(maxx[u]-minn[u]==1){ maxx[u]=floor(sqrt(maxx[u])); minn[u]=floor(sqrt(minn[u])); if(maxx[u]==minn[u]) { maxNum[u]=minNum[u]=r-l+1; lazy[u]=0; all[u]=maxx[u]; sum[u]=maxx[u]*maxNum[u]; } else if(maxx[u]-minn[u]==1) { lazy[u]+=maxx[u]-x; sum[u]=maxx[u]*maxNum[u]+minn[u]*minNum[u]; } return ; } return ; } pushDown(u,l,r); cd73 int mid=(l+r)>>1; if(t<=mid) Sqrt(l,mid,ul); else if(s>mid) Sqrt(mid+1,r,ur); else{Sqrt(l,mid,ul);Sqrt(mid+1,r,ur);} pushUp(u); } ll query(int l,int r,int u) { if(s<=l&&t>=r) return sum[u]; pushDown(u,l,r); int mid=(l+r)>>1; if(t<=mid) return query(l,mid,ul); else if(s>mid) return query(mid+1,r,ur); else return query(l,mid,ul)+query(mid+1,r,ur);; } int main() { int T,k; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n,1); while(m--) { scanf("%d%d%d",&k,&s,&t); if(k==1) { ll x;scanf("%lld",&x); add(1,n,1,x); } else if(k==2){ Sqrt(1,n,1); } else { printf("%lld\n",query(1,n,1)); } } } return 0; }
相关文章推荐
- 51NOD 1631 小鲨鱼在51nod小学 区间线段树
- 51Nod 1174 区间中最大的数 线段树
- 【51Nod】1672 - 区间交(线段树 & 贪心)
- 51nod 1376【线段树维护区间最大值】
- 51nod 1174区间中最大的数(线段树)
- HDU4027 - Can you answer these queries? - 线段树之区间开根号
- HDU-4027 开根号的线段树区间更新
- 51Nod 1174 区间中最大的数<线段树>
- hdu5828 Rikka with Sequence (线段树:区间开根+区间求和+区间加减)
- 51nod 1174 区间中最大的数【线段树】
- 51NOD 1672 区间交 线段树
- hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和
- 51nod 1672-区间交(线段树)
- 51nod 1672 区间交【线段树、multiset】
- 51nod-1376(线段树维护区间最值)
- COJ 0359 xjr考考你数据结构(根号2)线段树区间增加
- Rikka with Sequence---hdu5828(区间更新与查找 线段树)
- COJ 0358 xjr考考你数据结构(根号3)线段树区间修改
- BZOJ3211 花神游历各国(线段树,区间开根号)
- 51nod_1174 区间中最大的数(线段树模板)