hdu-4893
http://acm.hdu.edu.cn/showproblem.php?pid=1394
题意:
给定一个数组a,一开始数组里面的元素都是0,现在有三个操作:
操作1:给第k个数字加上d.
操作2:查询区间[l,r]的和.
操作3:改变区间[l,r]的每个数为最接近的斐波那契数列.其中斐波那契数列的f0=1,f1=1.
题解:
这题是单点更新+区间求和+区间更新,我们知道区间求和为了节省一点时间用的是懒惰标记来给每个被更改过的区间打上标记,而当我们需要计算这个区间的时候才将标记下推,使得值更新.
所以对于操作1的话,当我们更新单点的值得时候,由于当前区间在之前可能经历过区间的更改,所以我们需要维护两个数组来.第一个数组sum1用来维护所需要的输出的和,第二个数组sum2用来维护的是经过操作3之后的当前区间的和.
所以对于操作1的时候,需要判断一下该点有没有懒惰标记,如果有的话,该点的值用的就是经过操作3的sum2的值来更改,否则直接更改sum1的值.
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
#define pi acos(-1)
#define ls rt<<1
#define rs rt<<1|1
#define me0(s) memset(s,0,sizeof(s))
#define me1(s) memset(s,1,sizeof(s))
#define mef(s) memset(s,-1,sizeof(s))
#define meinf(s) memset(s,inf,sizeof(s))
#define llinf 1e18
#define inf 1e9
const int N=1e5+6;
ll fab[N];
int n,m;
ll lazy[N*4]; //lazy表示该区间的数要更改为斐波那契
ll a[N],sum1[N*4],sum2[N*4];//sum1表示原来的和,sum2表示更改后的值
void init(){
fab[0]=fab[1]=1;
for(int i=2;i<=100;i++){
fab[i]=fab[i-1]+fab[i-2];
}
}
ll find_fab(ll x){
ll ans=fab[0];
ll c=abs(fab[0]-x);
for(int i=0;i<=90;i++){
if(abs(x-fab[i])<c){
c=abs(x-fab[i]);
ans=fab[i];
}
}
return ans;
}
void pushup(int rt){
sum1[rt]=sum1[ls]+sum1[rs];
sum2[rt]=sum2[ls]+sum2[rs];
}
void pushdown(int rt){
if(lazy[rt]){
lazy[ls]=lazy[rs]=lazy[rt];
lazy[rt]=0;
sum1[ls]=sum2[ls];
sum1[rs]=sum2[rs];
}
}
void build(int l,int r,int rt){
if(l==r){
sum2[rt]=1;//初始状态所有数据为0,距离0最近的菲波那切数是1
return ;
}
int m=(l+r)/2;
build(l,m,ls);
build(m+1,r,rs);
pushup(rt);
}
void update1(int l,int r,int p,int c,int rt){
if(l==r){
if(lazy[rt]) sum1[rt]=sum2[rt]+c;
else sum1[rt]+=c;
sum2[rt]=find_fab(sum1[rt]);//更新sum1,sum2也要改变
lazy[rt]=0;
return ;
}
pushdown(rt);
int m=(l+r)/2;
if(p<=m) update1(l,m,p,c,ls);
if(p>m) update1(m+1,r,p,c,rs);
pushup(rt);
}
void update2(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
sum1[rt]=sum2[rt];
lazy[rt]=1;
return ;
}
pushdown(rt);
int m=(l+r)/2;
if(L<=m) update2(L,R,l,m,ls);
if(R>m) update2(L,R,m+1,r,rs);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
return sum1[rt];
}
pushdown(rt);
int m=(l+r)/2;
ll ans=0;
if(L<=m) ans+=query(L,R,l,m,ls);
if(R>m) ans+=query(L,R,m+1,r,rs);
return ans;
}
int main(int argc, char * argv[]){
init();
while(scanf("%d%d",&n,&m)!=EOF){
me0(sum1);
me0(lazy);
build(1,n,1);
while(m--){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
update1(1,n,l,r,1);
}
else if(op==2){
printf("%lld\n",query(l,r,1,n,1));
}
else{
update2(l,r,1,n,1);
}
}
}
return 0;
}