1 1 2 1 1 5 4 1 1 7 1 3 17 3 2 4 2 1 5
0 22
题意:
给你长度为n的序列。序列初始值都为0.m组询问。支持三种操作。
1 k d 给第k个数加上d。
2 l r 询问[l.r]区间和。
3 l r 把所有[l,r]的值a[i]变成与a[i]值最相近的费布拉奇数。
f[0]=1,f[1]=1.f[i]=f[i-1]+f[i-2].
1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, |d| < 231
思路:
本来不打算写题解的。但是搜了下网上的题解。发现方法都不是很好。于是打算分享下自己的方法。
对于前两个操作肯定很简单啦。关键是现在有了第三个操作。其实很简单。我们只需在线段树的没个结点维护两个信息sum表示原区间和。和假如把整个区间变成费布拉奇数的区间和fsum.再加上一个ff标记表示区间是否都是费布拉奇数。对于add操作。单点更新。没什么优化只是更新后沿途更新下sum,fsum.ff就行了。只是更新叶子结点的fsum.先打个大小90的费布拉奇数列表。再二分找最近的值就行。。对于3操作就更简单了。如果当前区间的ff标记为1就不用更新了。不然就往下更新。直到区间匹配让后sum=fsum。再打上标记就行了。对于询问操做跟区间求和没什么区别。需要注意的是数据要爆int。这个应该自己可以看出来。
详细见代码:
#include<algorithm> #include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100010; typedef long long ll; #define lson L,mid,ls #define rson mid+1,R,rs ll f[110]; ll sum[maxn<<2],fsum[maxn<<2]; bool ff[maxn<<2]; ll getf(ll x) { int low=0,hi=90,mid,ans; if(x<=0) return 1LL; while(low<=hi) { mid=(low+hi)>>1; if(f[mid]<=x) ans=mid,low=mid+1; else hi=mid-1; } if(f[ans+1]-x<x-f[ans]) return f[ans+1]; else return f[ans]; } void build(int L,int R,int rt) { ff[rt]=false; sum[rt]=0; fsum[rt]=R-L+1;//比赛时短路.fsum=1.wa了一发。 if(L==R) return; int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; build(lson); build(rson); } void PushDown(int L,int R,int rt) { int ls=rt<<1,rs=ls|1; ff[rt]=false; ff[ls]=ff[rs]=true; sum[ls]=fsum[ls]; sum[rs]=fsum[rs]; } void add(int L,int R,int rt,int p,ll v) { if(L==R) { ff[rt]=false; sum[rt]+=v; fsum[rt]=getf(sum[rt]); return ; } if(ff[rt]) PushDown(L,R,rt); int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; if(p<=mid) add(lson,p,v); else add(rson,p,v); sum[rt]=sum[ls]+sum[rs]; fsum[rt]=fsum[ls]+fsum[rs]; } void update(int L,int R,int rt,int l,int r) { if(ff[rt]) return; if(l<=L&&R<=r) { ff[rt]=true; sum[rt]=fsum[rt]; return; } int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; if(l<=mid) update(lson,l,r); if(r>mid) update(rson,l,r); if(ff[ls]&&ff[rs]) ff[rt]=true; sum[rt]=sum[ls]+sum[rs]; fsum[rt]=fsum[ls]+fsum[rs]; } ll qu(int L,int R,int rt,int l,int r) { ll tp=0; if(l<=L&&R<=r) return sum[rt]; if(ff[rt]) PushDown(L,R,rt); int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; if(l<=mid) tp=qu(lson,l,r); if(r>mid) tp+=qu(rson,l,r); sum[rt]=sum[ls]+sum[rs]; fsum[rt]=fsum[ls]+fsum[rs]; return tp; } int main() { int i,n,m,cmd,a; ll b; f[0]=f[1]=1; for(i=2;i<=90;i++) f[i]=f[i-1]+f[i-2]; while(~scanf("%d%d",&n,&m)) { build(1,n,1); for(i=0;i<m;i++) { scanf("%d%d%I64d",&cmd,&a,&b); if(cmd==1) add(1,n,1,a,b); else if(cmd==2) printf("%I64d\n",qu(1,n,1,a,b)); else update(1,n,1,a,b); } } return 0; }
hdu 4893 (多校1007)Wow! Such Sequence!(线段树&二分&思维),布布扣,bubuko.com
hdu 4893 (多校1007)Wow! Such Sequence!(线段树&二分&思维)
原文:http://blog.csdn.net/bossup/article/details/38276267