题目链接:戳这里
3211: 花神游历各国
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 4119 Solved: 1504
[ Submit][ Status][ Discuss]
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
Source
一道还算简单的线段树。看到题目中的区间操作和查询很容易让人想到线段树,但区间开方好像不满足区间加和性质?
所以我们必须修改到每个叶节点上,但这么做就会TLE。
观察数据:因为是向下取整,所以经过几次操作后就会有区间变成1,显然全是1的区间我们就没必要继续修改下去了,这样就能大大减少复杂度。
对于线段树的每个节点,维护一个lazy或区间最大值,当lazy大于6或区间最大值<=1的时候就直接返回。
代码:
#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
typedef long long LL;
int read()
{
char c;int sum=0,f=1;c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
int n,ql[maxn];
int m;
LL sum[maxn*4];
int lazy[maxn*4];
void pushup(int id)
{
sum[id]=sum[id<<1]+sum[id<<1|1];
return;
}
void build(int id,int l,int r)
{
if(l==r)
{
sum[id]=ql[l];
return;
}
int mid=l+r>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
void update(int id,int ql,int qr,int l,int r)
{
if(l>=ql && r<=qr)
{
lazy[id]++;
if(l==r)
{
sum[id]=sqrt(sum[id]);
return;
}
}
int mid=(l+r)>>1,lson=(id<<1),rson=(id<<1|1);
if(lazy[lson]<6 && ql<=mid) update(lson,ql,qr,l,mid);
if(lazy[rson]<6 && qr>mid) update(rson,ql,qr,mid+1,r);
pushup(id);
return;
}
LL query(int id,int ql,int qr,int l,int r)
{
if(l>=ql && r<=qr)
return sum[id];
LL ans=0;
int mid=(l+r)>>1;
if(ql<=mid) ans+=query(id<<1,ql,qr,l,mid);
if(qr>mid) ans+=query(id<<1|1,ql,qr,mid+1,r);
return ans;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
ql[i]=read();
build(1,1,n);
m=read();
for(int i=1;i<=m;i++)
{
int f=read(),l=read(),r=read();
if(f==1) printf("%lld\n",query(1,l,r,1,n));
if(f==2) update(1,l,r,1,n);
}
return 0;
}