校门外有很多树

问题描述

校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,读入l,r表示在l~r之间种上的一种树
K=2,读入l,r表示询问l~r之间能见到多少种树
(0<l,r)

输入格式

第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作

输出格式

对于每个k=2输出一个答案

样例输入

5 4
1 1 3
2 2 5
1 2 4
2 3 5

样例输出

1
2

数据范围

20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000


题解

cnt1[]记录下某点及以前共出现了多少种树,
cnt2[]记录某点及以前共有多少段完整的区间。
因此询问(x,y)的答案为cnt1[y]-cnt2[x-1]
对于修改操作,将cnt1在[l,∞)内的数全部加一,将cnt2在[r,∞)内的数全部加一。
用线段树进行区间修改。具体见代码(我用的动态开点)


代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int tot=2,cnt[500000],ls[500000],rs[500000],maxr,lazy[500000];
void putdown(int x)
{
    if(!ls[x])ls[x]=++tot;
    if(!rs[x])rs[x]=++tot;
    int v=lazy[x];
    cnt[ls[x]]+=v;
    cnt[rs[x]]+=v;
    lazy[ls[x]]+=v;
    lazy[rs[x]]+=v;
    lazy[x]=0;
}
void xiu(int now,int l,int r,int x,int y)
{
    if(lazy[now])putdown(now);
    if(x<=l&&y>=r){
        cnt[now]++;
        lazy[now]++;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
    {
        if(!ls[now])ls[now]=++tot;
        xiu(ls[now],l,mid,x,y);
    }
    if(y>mid)
    {
        if(!rs[now])rs[now]=++tot;
        xiu(rs[now],mid+1,r,x,y);
    }
}
int get(int now,int l,int r,int x)
{
    if(l==r)return cnt[now];
    if(lazy[now])putdown(now);
    int mid=(l+r)>>1;
    if(x<=mid)return get(ls[now],l,mid,x);
    else return get(rs[now],mid+1,r,x);
}
int main()
{
    int i,m,x,y;
    scanf("%d%d",&maxr,&m);
    while(m--)
    {
        scanf("%d%d%d",&i,&x,&y);
        if(i==1)xiu(1,0,maxr,x,maxr),xiu(2,0,maxr,y,maxr);
        else printf("%d\n",get(1,0,maxr,y)-get(2,0,maxr,x-1));
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值