【tyvj1473】校门外的树3

tyvj1473

这道题可以用两个树状数组来做把每次更新的端点分别插入两个树状数组,在查询区间时,之前更新的区间会对当前查询区间产生影响的条件是
更新的末端点大于查询的始端点且更新的始端点小于等于查询的末端点,那么由于如果某次更新的始端点大于查询的末端点,那么这次更新的末端点也大于查询的末端点
因而我们所求的就是
已更新线段的末端点不小于查询的始端点的个数 - 已更新线段的始端点大于查询的末端点的个数

能用树状数组就不用线段树咯。。。毕竟10分钟A掉的题目就不麻烦写几种方法了

include<cstdio>
using namespace std;

const int maxn = 50000 + 10;
int n, m, c1[maxn], c2[maxn];

int lowbit(int x) { return x&-x; }

void add1(int x){
    while(x <= n){
        c1[x]++;
        x += lowbit(x);
    }
}
void add2(int x){
    while(x <= n){
        c2[x]++;
        x += lowbit(x);
    }
}

int sum1(int x){
    int cnt = 0;
    while(x > 0){
        cnt += c1[x];
        x -= lowbit(x);
    }
    return cnt;
}
int sum2(int x){
    int cnt = 0;
    while(x > 0){
        cnt += c2[x];
        x -= lowbit(x);
    }
    return cnt;
}

int main(){
    scanf("%d %d", &n, &m);
    int k, l, r;
    while(m--){
        scanf("%d %d %d",&k, &l, &r);
        if(k == 1){
            add1(l);
            add2(r);
        }
        else
            printf("%d\n",( sum2(n)-sum2(l-1) ) - ( sum1(n)-sum1(r) ));
    }
    return 0;
}

hzwer学长的线段树代码附上

#include<cstdio>
#include<iostream>
using namespace std;
int n,m;
struct data{
    int l,r;
    int left,right;
}tr[200001];
void build(int k,int s,int t)
{
    tr[k].left=s;tr[k].right=t;
    if(s==t)return;
    int mid=(s+t)>>1;
    build(k<<1,s,mid);
    build(k<<1|1,mid+1,t);
}
void insertl(int k,int x,int y)
{
    int l=tr[k].left,r=tr[k].right;
    if(l==x&&y==r){tr[k].l++;return;}
    int mid=(l+r)>>1;
    if(y<=mid)insertl(k<<1,x,y);
    else if(x>mid)insertl(k<<1|1,x,y);
    else {
        insertl(k<<1,x,mid);
        insertl(k<<1|1,mid+1,y);
    }
}
void insertr(int k,int x,int y)
{
    int l=tr[k].left,r=tr[k].right;
    if(l==x&&y==r){tr[k].r++;return;}
    int mid=(l+r)>>1;
    if(y<=mid)insertr(k<<1,x,y);
    else if(x>mid)insertr(k<<1|1,x,y);
    else {
        insertr(k<<1,x,mid);
        insertr(k<<1|1,mid+1,y);
    }
}
int askl(int k,int x)
{
    int l=tr[k].left,r=tr[k].right;
    if(l==r)return tr[k].l;
    int mid=(l+r)>>1;
    if(x<=mid)return tr[k].l+askl(k<<1,x);
    else return tr[k].l+askl(k<<1|1,x);
}
int askr(int k,int x)
{
    int l=tr[k].left,r=tr[k].right;
    if(l==r)return tr[k].r;
    int mid=(l+r)>>1;
    if(x<=mid)return tr[k].r+askr(k<<1,x);
    else return tr[k].r+askr(k<<1|1,x);
}
int main()
{
    int total=0,ans;
    scanf("%d%d",&n,&m);
    build(1,0,n);
    for(int i=1;i<=m;i++)
       {
           int t,a,b;
           scanf("%d%d%d",&t,&a,&b);
           if(t==1){
              insertl(1,0,a-1);
              insertr(1,b+1,n);
              total++;
              }
           else
           {
              ans=askr(1,a)+askl(1,b);
              printf("%d\n",total-ans);
           }
       }
    return 0;
}

hzwer学长博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值