hdu4893 Wow! Such Sequence! 線段樹
阿新 • • 發佈:2019-02-08
題意:對一列數字進行多種操作 把一段數字變成最近的斐波那契數 統計一段數字的和 增加單個數字的權值
解法:由於要進行成段變成斐波那契,這就需要打標記,而新增單個的權值也需要標記 這樣我們就需要開兩個標記
然後add標記是需要新增的值變成斐波那契數列
然後對於已經修改過的段我們就可以知道這一段就都是斐波那契數了
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define ll __int64 #define ls (rt<<1) #define rs (rt<<1|1) #define mid ((l+r)>>1) #define maxn 111111 ll num[maxn]; ll sum[maxn<<2],add[maxn<<2]; int set[maxn<<2]; ll f[111],x; void up(int rt,int l,int r){ sum[rt]=sum[ls]+sum[rs]; add[rt]=add[ls]+add[rs]; } void build(int rt,int l,int r){ sum[rt]=0;set[rt]=-1; if(l==r){ add[rt]=1; return ; } build(ls,l,mid); build(rs,mid+1,r); up(rt,l,r); } void down(int rt,int l,int r){ if(set[rt]!=-1){ sum[ls]+=add[ls]; sum[rs]+=add[rs]; add[ls]=add[rs]=0; set[ls]=set[rs]=1; set[rt]=-1; } } void ad(int rt,int l,int r,int L,int R,ll w){ if(L<=l&&r<=R){ sum[rt]+=w; int c=(int)(lower_bound(f,f+75,sum[rt])-f); if(c==0){ add[rt]=f[0]-sum[rt]; } else{ if(f[c]==sum[rt]){return ;} else if(sum[rt]-f[c-1]<=f[c]-sum[rt]){ add[rt]=f[c-1]-sum[rt]; } else add[rt]=f[c]-sum[rt]; } return ; } down(rt,l,r); if(L<=mid)ad(ls,l,mid,L,R,w); if(mid<R)ad(rs,mid+1,r,L,R,w); up(rt,l,r); } void ins(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R){ sum[rt]+=add[rt]; add[rt]=0; set[rt]=1; return ; } down(rt,l,r); if(L<=mid)ins(ls,l,mid,L,R); if(mid<R)ins(rs,mid+1,r,L,R); up(rt,l,r); } ll query(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R){ return sum[rt]; } down(rt,l,r); ll res=0; if(L<=mid)res+=query(ls,l,mid,L,R); if(mid<R)res+=query(rs,mid+1,r,L,R); return res; } int n,m; int main(){ f[0]=1;f[1]=1; for(int i=2;i<=79;++i) f[i]=f[i-1]+f[i-2]; while(~scanf("%d%d",&n,&m)){ build(1,1,n); int op,a,b; for(int i=1;i<=m;++i){ scanf("%d%d%d",&op,&a,&b); if(op==1){ ad(1,1,n,a,a,b); } else if(op==2){ printf("%I64d\n",query(1,1,n,a,b)); } else if(op==3){ ins(1,1,n,a,b); } } } return 0; }