csu2107 千万别用树套树 (权值线段树*2)

问题描述

Bobo 精通数据结构!他想维护一个线段的集合 S。初始时,S 为空。他会依次进行 q 次操作,操作有 2 种。

类型 1:给出 l, r,向集合 S 中插入线段 [l, r].
类型 2:给出 l, r,询问满足 [x, y]∈S 且 x ≤ l ≤ r ≤ y 的线段 [x, y] 数量。
帮 Bobo 求出每次询问的答案。

1 ≤ n, q ≤ 105
ti ∈ {1, 2}
1 ≤ li ≤ ri ≤ n
对于 ti = 2 的操作,ri − li ≤ 2 成立。
数据组数不超过 10.

Input

输入文件包含多组数据,请处理到文件结束。

每组数据的第一行包含 2 个整数 n 和 q. 其中 n 表示操作中 r 的最大值。

接下来 q 行中的第 i 行包含 3 个整数 ti, li, ri,表示第 i 个操作属于类型 ti,对应的参数是 li 和 ri.

Output

对于每个类型 2 的询问,输出 1 个整数表示对应的数量。

Sample Input

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

Sample Output

1
1
2

思路:

开两棵权值线段树
一棵维护区间左端点L的数量
一棵维护区间右端点R的数量
查询的时候,答案就是:
总区间数量 - 左端点大于L的区间数量 - 右端点小于R的区间数量

code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxm=1e5+5;
struct Tree{
    int a[maxm<<2];
    void init(){//初始化
        memset(a,0,sizeof a);
    }
    void update(int x,int l,int r,int node){//单点增加
        a[node]++;
        if(l==r)return ;
        int mid=(l+r)/2;
        if(x<=mid)update(x,l,mid,node*2);
        else update(x,mid+1,r,node*2+1);
    }
    int ask(int st,int ed,int l,int r,int node){//区间求和
        if(a[node]==0)return 0;
        if(st<=l&&ed>=r)return a[node];
        int mid=(l+r)/2;
        int ans=0;
        if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
        if(ed>=mid+1)ans+=ask(st,ed,mid+1,r,node*2+1);
        return ans;
    }
}t1,t2;
int n,q;
signed main(){
    while(scanf("%d%d",&n,&q)!=EOF){
        t1.init();//reset
        t2.init();
        int cnt=0;//总区间个数
        while(q--){
            int d,x,y;
            scanf("%d%d%d",&d,&x,&y);
            if(d==1){//添加
                cnt++;//区间个数加1
                t1.update(x,1,n,1);
                t2.update(y,1,n,1);
            }else{//查询
                int ans=cnt;
                ans-=t1.ask(x+1,n,1,n,1);//减去左端点大于l的区间数量
                ans-=t2.ask(1,y-1,1,n,1);//减去右端点小于r的区间数量
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值