vijos 1448 校门外的树 (不是05年普及组那题)

描述

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

格式

输入格式

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

输出格式

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

样例1

样例输入1

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

样例输出1

1
2

限制

1s

提示

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

来源

dejiyu@CSC WorkGroup

 

这道题是典型的区间问题 

但由于树的种类比较多,直接维护可能会超时

于是就用括号序列来做 。

比方说[2,10] 种树 在2 放一个左括号,10放一个右括号

统计[2,10]内有多少树的话,就找[2,10]内左括号的数量减去[1,2]内右括号的数量

屠龙宝刀点击就送

#include <cstring>
#include <cstdio>

typedef long long LL;
struct tree
{
    LL l,r;
    LL zk,yk;
}t[500000*4+1];
LL n,m,ans;
void build(LL k,LL l,LL r)
{
    t[k].l=l;t[k].r=r;
    if(l==r) return;
    LL mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
void ptz(LL l,LL k)
{
    if(t[k].l==l&&t[k].r==l) t[k].zk++;
    else
    {
        LL mid=(t[k].l+t[k].r)>>1;
        if(l>mid) ptz(l,k<<1|1);
        else if(l<=mid) ptz(l,k<<1);
        t[k].zk=t[k<<1].zk+t[k<<1|1].zk;
    }
}
void pty(LL l,LL k)
{
    if(t[k].l==l&&t[k].r==l) t[k].yk++;
    else
    {
        LL mid=(t[k].l+t[k].r)>>1;
        if(l>mid) pty(l,k<<1|1);
        else if(l<=mid) pty(l,k<<1);
        t[k].yk=t[k<<1].yk+t[k<<1|1].yk;
    }
}
LL queryz(LL l,LL r,LL k)
{
    if(t[k].l>=l&&t[k].r<=r) return t[k].zk;
    LL mid=(t[k].l+t[k].r)>>1;
    if(r<=mid) return queryz(l,r,k<<1);
    else if(l>mid) return queryz(l,r,k<<1|1);
    else return queryz(l,mid,k<<1)+queryz(mid+1,r,k<<1|1);
}
LL queryy(LL l,LL r,LL k)
{
    if(t[k].l>=l&&t[k].r<=r) return t[k].yk;
    LL mid=(t[k].l+t[k].r)>>1;
    if(r<=mid) return queryy(l,r,k<<1);
    else if(l>mid) return queryy(l,r,k<<1|1);
    else return queryy(l,mid,k<<1)+queryy(mid+1,r,k<<1|1);
}
void qr(LL &x)
{
    x=0;bool f=0;
    char ch=getchar();
    while(ch>'9'||ch<'0')
    {
        if(ch=='-') f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+(int)ch-48;
        ch=getchar();
    }
    x=(f==1)?((~x)+1):x;
}
int main()
{
    qr(n);qr(m);
    build(1,1,n);
    for(LL x,y,z;m--;)
    {
        qr(x);qr(y);qr(z);
        if(x==1) ptz(y,1),pty(z,1);
        else
        {
            LL ans=queryz(1,z,1);
            if(y!=1)
            ans-=queryy(1,y-1,1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ruojisun/p/6575981.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值