您的位置:首页 > 其它

HDU5828(线段树好题,区间加,区间求根号,吉老师在51nod直播讲过这道题,相应的还有区间取模)

2017-07-22 22:21 253 查看
题解:区间加,区间和不用说。重点在区间取模,首先,就算一个很大的n,几次根号之后就会很小。

我们可以思考一下,如果一个区间内的极差>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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: