HDU 4893 2014多校三 线段树
给定一个初始都为0的序列,有三种操作,前两种比较正常,一个是对某个位置的数add k,另一个是query区间和。然后比较麻烦的是第三个操作,把某个区间里面的每个值改成离它最近的Fibonacci数,如果存在左右两个离它近的,优先取左边数值小的
一看到前两个操作马上就想上手敲树状数组,后来看到第三个就有点傻眼了,思维当时一直停留在怎么快速改值。。但忽略了题目本身要求什么,只有操作2才是输出,也就是只要求区间和值而且,其他两个都是操作而已,在聪哥的提醒下,知道对线段树开两个值记录+一个懒惰标记,一个值d记录正常的区间和值,另一个sf记录当前的fibanacci数值和
懒惰标记记录当前区间是否被3操作过,若被标记了,下次query就是返回sf,否则返回d。
不过一开始思路还是有点不清晰,还WA了几发。明显按上面的转化就是一个普通的单点更新+懒惰标记+区间查询的线段树了嘛
主要错在pushdown函数和3操作处理上。没分清模块
首先3操作命名为fix,fix找到对应的区间后,就进行懒惰标记,顺便把当前区间d改为sf值,然后向上传递。
add操作,首先,找到最后单点即进行更新操作,否则pushdown,把懒惰标记传递下去,在标记里面也是要对d=sf操作的,最后向上传递结果
query就更明显了,找区间return sf 或者 d,没找到就先pushdown
一开始糊里糊涂,pushdown又没push好,还没修改当前的值
比赛的时候还是有点糊里糊涂,线段树功底还不够,还要继续练
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define LL __int64 using namespace std; const int N = 100010; LL f[100]; LL d[N<<2],flag[N<<2],sf[N<<2]; LL pref[N]; int n,q; void init() { LL tmp=1LL<<60; f[0]=f[1]=1; for (int i=2;i<=90;i++){ f[i]=f[i-1]+f[i-2]; } } void build(int rt ,int l,int r) { flag[rt]=d[rt]=0; if (l>=r){ sf[rt]=1; return; } int mid=(l+r)>>1; build(lson); build(rson); sf[rt]=sf[rt<<1]+sf[rt<<1|1]; } void change(int rt) { d[rt]=sf[rt]; } void up(int rt,int l,int r) { d[rt]=d[rt<<1]+d[rt<<1|1]; sf[rt]=sf[rt<<1]+sf[rt<<1|1]; } void pushdown(int rt,int l,int r) { int mid=(l+r)>>1; if (flag[rt]==0 || l>=r) return; flag[rt<<1]=flag[rt<<1|1]=flag[rt]; d[rt<<1]=sf[rt<<1]; d[rt<<1|1]=sf[rt<<1|1]; flag[rt]=0; } void fix(int L,int R,int rt,int l,int r) { if (flag[rt]==1) return; if (L<=l && r<=R){ flag[rt]=1; d[rt]=sf[rt]; return; } int mid=(l+r)>>1; if (R<=mid) fix(L,R,lson); else if (L>mid) fix(L,R,rson); else{ fix(L,R,lson); fix(L,R,rson); } if (flag[rt<<1]==1 && flag[rt<<1|1]==1){ flag[rt]=1; } up(rt,l,r); } void add(int loc,LL val,int rt,int l,int r) { if (l>=r) { flag[rt]=0; d[rt]+=val; int loc=lower_bound(f,f+90,d[rt])-f; sf[rt]=f[loc]; if (loc>0){ if (d[rt]-f[loc-1]<=f[loc]-d[rt]){ sf[rt]=f[loc-1]; } } return; } pushdown(rt,l,r); int mid=(l+r)>>1; if (loc<=mid) add(loc,val,lson); else add(loc,val,rson); up(rt,l,r); } LL query(int L,int R,int rt,int l,int r) { if (L<=l && r<=R){ if (flag[rt]) return sf[rt]; else return d[rt]; } pushdown(rt,l,r); int mid=(l+r)>>1; if (R<=mid) return query(L,R,lson); else if (L>mid) return query(L,R,rson); else { LL ret1=query(L,R,lson); LL ret2=query(L,R,rson); return ret1+ret2; } } int main() { init(); int op; while (scanf("%d%d",&n,&q)!=EOF) { build(1,1,n); while (q--) { scanf("%d",&op); if (op==1){ int a; LL b; scanf("%d%I64d",&a,&b); add(a,b,1,1,n); } else if (op==2){ int a,b; scanf("%d%d",&a,&b); LL ans=query(a,b,1,1,n); printf("%I64d\n",ans); } else{ int a,b; scanf("%d%d",&a,&b); fix(a,b,1,1,n); } } } return 0; }