离散化后线段树

正常的线段树是这样的

[1,10]->[1,5]+[6,10];

我们统计区间和的时候也很方便每个区间的r-l+1就是区间长度

现在的问题是如果数据范围太大,维护一段区间的和就不简单了

例如以下对应关系

1    2     3    4    5    6

10  20   30  40  50  60

当区间[10,20]修改为1,线段树操作时为[1,2]修改为1,

当区间[20,30]修改为1,线段树操作时为[2,3]修改为1,

当我们循问区间[10,30]时,线段树操作时为询问[1,3]

如果还是按照之前的想法,[1,3]=[1,2]+[3,3]=(20-10+1)+(1-1+1)=12显然是错误的

我们需要重新定义线段

[a,b)=[a,mid)+[mid,b)

修改[10,20]是我们实际修改[10,21),修改[20,30]是我们实际修改[20,31)

询问[10,30],实际询问[10,31)

重新建立对应关系

1     2      3     4

10   20    21   31

修改[10,20],将[1,3)修改为1

修改[20,30],将[1,3)修改为1

询问[10,30],就是询问[1,4)

[1,4)=[1,2)+[2,4)

而[1,3)修改为1,[1,3)修改为1,使得[1,2)和[2,4)都为1

[1,4)=[1,2)+[2,4)=(20-10)+(31-20)=21

而[10,30]=(30-10+1)=21

 

实现方法:

将所有用到的区间[a,b],化成[a,b+1),将a和b+1两个数用于离散

区间和变为[x,y)=f[y]-f[x],函数f表示离散后的映射关系。

其余操作不变

区间赋值(赋值为1)的操作

void pushdown(int x,int l,int r,node *t)
{
    if (t[x].d)
    {
        int mid=l+r>>1;
        t[x<<1].d=1; t[x<<1].s=f[mid]-f[l];
        t[x<<1|1].d=1; t[x<<1|1].s=f[r]-f[mid];
        t[x].d=0;
    }
}

void updata(int x,int l,int r,int fl,int fr,node *t)
{
    if (l==fl && r==fr)
    {
        t[x].d=1;
        t[x].s=f[r]-f[l];
        return;
    }
    pushdown(x,l,r,t);
    int mid=l+r>>1;
    if (fr<=mid) updata(x<<1,l,mid,fl,fr,t);else
    if (fl>=mid) updata(x<<1|1,mid,r,fl,fr,t);else
    {
        updata(x<<1,l,mid,fl,mid,t);
        updata(x<<1|1,mid,r,mid,fr,t);
    }
    t[x].s=t[x<<1].s+t[x<<1|1].s;
}

询问操作

int query(int x,int l,int r,int fl,int fr,node *t)
{
    if (l==fl && r==fr)return t[x].s;
    pushdown(x,l,r,t);
    int mid=l+r>>1;
    if (fr<=mid) return query(x<<1,l,mid,fl,fr,t);else
    if (fl>=mid) return query(x<<1|1,mid,r,fl,fr,t);else
        return query(x<<1,l,mid,fl,mid,t)+query(x<<1|1,mid,r,mid,fr,t);
}

 

离散化操作

for (int i=1;i<=q;i++)
{
    scc(,a[i],b[i]);
    f[++cnt]=a[i];
    f[++cnt]=b[i]+1;
}
f[++cnt]=n+1;
sort(f+1,f+cnt+1);
cnt=unique(f+1,f+cnt+1)-f-1;
int nn=lb(f+1,f+cnt+1,n+1)-f;

使用方法

for (int i=1;i<=q;i++)
{
    int x=lower_bound(f+1,f+cnt+1,a[i])-f,y=lower_bound(f+1,f+cnt+1,b[i]+1)-f;
    updata(1,1,nn,x,y,t);
    query(1,1,nn,x,y,t);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值