hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893

开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对

参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdin)

const int MAXN =100000+100;
ll ff[105];
ll num[MAXN];

void init()
{
    ff[0]=ff[1]=1;
    for(int i=2;i<105;i++)
        ff[i]=ff[i-1]+ff[i-2];
}

ll cal(ll x)
{
    if(x == 0)return 1;
    int idx=lower_bound(ff,ff+105,x)-ff;
    //if(ff[idx] == x || idx==0)return ff[idx];//
    if(x-ff[idx-1]<=ff[idx]-x)return ff[idx-1];
    else return ff[idx];
}

struct Node{
    int l,r;
    ll sum;
    ll add;//区间内某个值被改过,如果进行FF操作,需要将当前结点dfs
    int flag;//1,区间内有值变过/初始的时候,如果有fi区间更新的话需要重新更新 0--已经更新过程斐波那契,不需要更新
}nodes[MAXN*4];

void build(int rt, int l, int r)
{
    nodes[rt].l=l;
    nodes[rt].r=r;
    nodes[rt].sum=0;
    nodes[rt].add=1;//没有做过fi修改
    nodes[rt].flag=0;
    if(l==r)
    {
        num[l]=0;
        return;
    }
    int mid=(l+r)/2;
    build(ls(rt),l,mid);
    build(rs(rt),mid+1,r);
    if(nodes[rt].l==nodes[rt].r)return;
    nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
    nodes[rt].add=nodes[ls(rt)].add+nodes[rs(rt)].add;
}

/*void dfs(int rt)
{
    if(0 == nodes[rt].flag)return;//已经修改过斐波那契
    if(0 == nodes[rt].add)return;//区间内值没有做过修改
    nodes[rt].flag=0;//改过
    nodes[rt].add=0;
    if(nodes[rt].l == nodes[rt].r)
    {
        nodes[rt].sum=num[nodes[rt].l]=cal(num[nodes[rt].l]);
        return;
    }
    dfs(ls(rt));
    dfs(rs(rt));
    nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
}*/
void pushdown(int rt)
{
    if(nodes[rt].flag && nodes[rt].l==nodes[rt].r)
    {
        nodes[rt].sum=nodes[rt].add;
        nodes[rt].flag=0;
        return;
    }
    if(nodes[rt].flag)
    {
        nodes[ls(rt)].flag=nodes[rs(rt)].flag=1;
        nodes[ls(rt)].sum=nodes[ls(rt)].add;
        nodes[rs(rt)].sum=nodes[rs(rt)].add;
        nodes[rt].flag=0;
    }
}
void modify(int rt, int p, ll v)
{
    if(nodes[rt].l==nodes[rt].r)
    {

        nodes[rt].sum+=v;
        nodes[rt].add=cal(nodes[rt].sum);
        num[nodes[rt].l]+=v;
        nodes[rt].flag=0;
        return;
    }
    pushdown(rt);
    //nodes[rt].add=1;//该节点的区间被修改过值,如果进行FF,需要dfs
    int mid=(nodes[rt].l+nodes[rt].r)/2;
    if(p<=mid)modify(ls(rt),p,v);
    else modify(rs(rt),p,v);
    if(nodes[rt].l==nodes[rt].r)return;
    nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
    nodes[rt].add=nodes[ls(rt)].add+nodes[rs(rt)].add;/////////
}

void update(int rt, int l, int r)
{
    if(nodes[rt].l==l && nodes[rt].r==r)
    {
        nodes[rt].flag=1;
            //需要修改
        nodes[rt].sum=nodes[rt].add;
        return;
    }
    pushdown(rt);
    int mid=(nodes[rt].l+nodes[rt].r)/2;
    if(r<=mid)update(ls(rt),l,r);
    else
    {
        if(l>mid)update(rs(rt),l,r);
        else
        {
            update(ls(rt),l,mid);
            update(rs(rt),mid+1,r);
        }
    }
    if(nodes[rt].l==nodes[rt].r)return;
    nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
    nodes[rt].add=nodes[ls(rt)].add+nodes[rs(rt)].add;
}

ll query(int rt, int l, int r)
{
    //if(nodes[rt].flag && nodes[rt].add)dfs(rt);
    if(nodes[rt].l == l && nodes[rt].r==r)
    {
        return nodes[rt].sum;
    }
    pushdown(rt);
    int mid=(nodes[rt].l+nodes[rt].r)/2;
    ll ret=0;
    if(r<=mid)ret= query(ls(rt),l,r);
    else
    {
        if(l>mid)ret= query(rs(rt),l,r);
        else
        {
            ret= query(ls(rt),l,mid)+query(rs(rt),mid+1,r);
        }
    }
    if(nodes[rt].l!=nodes[rt].r)
    {
         nodes[rt].sum=nodes[ls(rt)].sum+nodes[rs(rt)].sum;
         nodes[rt].add=nodes[ls(rt)].add+nodes[rs(rt)].add;
    }
    return ret;
}

int main()
{
    //IN("hdu4893.txt");
    int n,m,op,l,r;
    init();
    while(~scanf("%d%d",&n,&m))
    {
        build(1,1,n);
        while(m--)
        {
            scanf("%d",&op);
            scanf("%d%d",&l,&r);
            if(op == 1)
            {
                modify(1,l,r);
            }
            if(op == 3)
            {
                update(1,l,r);
            }
            if(op == 2)
            {
                printf("%I64d\n",query(1,l,r));
            }
        }
    }
    return 0;
}

hdu 4893 线段树 --- 也是两个变 类似双标记,布布扣,bubuko.com

时间: 2024-07-30 13:35:53

hdu 4893 线段树 --- 也是两个变 类似双标记的相关文章

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4893 线段树的 点更新 区间求和

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2067    Accepted Submission(s): 619 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #

HDU 4339 线段树区间合并

Query Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2573    Accepted Submission(s): 851 Problem Description You are given two strings s1[0..l1], s2[0..l2] and Q - number of queries.Your task

HDU 3308 线段树(区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3896    Accepted Submission(s): 1766 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index