「一本通 4.1 例 3」校门外的树 (loj10115)

题目描述

原题来自:Vijos P1448

校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两种操作:

  • K=1,读入 l,r表示在 lr 之间种上一种树,每次操作种的树的种类都不同;
  • K=2,读入 l,r表示询问 lr之间有多少种树。

注意:每个位置都可以重复种树。

输入格式

第一行 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% 的数据,1≤n,m≤100
对于 60% 的数据,1≤n≤10^3,1≤m≤5×10^4

对于 100% 的数据,1≤n,m≤5×10^4,保证 l,r>0

 

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const long long maxn=50010;
int n, m;
inline void qread(int &x){
    x = 0;
    int ch = getchar();
    while(ch < '0' || ch > '9')        ch =getchar();
    while(ch >='0' && ch <= '9')    x = 10 * x + ch - 48, ch = getchar();
}
struct BItree{
    int data[maxn];
    BItree(){
        memset(data, 0, sizeof(data));
    }
    void add(int x){
        for(; x<=maxn-10; x += (x&-x))
            data[x]++;
    }
    int sum(int x){
        int ans = 0;
        for(; x; x -= (x&-x))
            ans += data[x];
        return ans;    
    }
};
int main(void)
{
    BItree left, right;
    qread(n), qread(m);
    while(m--){
        int x, y, z;
        qread(x), qread(y), qread(z);
        if(x-1){
            printf("%d\n", left.sum(z) - right.sum(y - 1));
        }else{
            left.add(y);
            right.add(z);
        }
    }
}

 

思路:

  建两个树状数组,其中一个存储从1-n区间左端点的数目,另一个存储1-n区间右端点的数目,则l-r内树的种数即为right(r) - left(l-1).

 

​​,保证 l,r>0l,r\gt 0l,r>0。3​​,1m5×104​​;
对于 100%100\%100% 的数据,1≤n,m≤5×1041\le n,m\le 5\times 10^41n,m5×104​​,保证 l,r>0l,r\gt 0l,r>0。

posted @ 2018-08-13 20:58  junk_yao  阅读(983)  评论(0)    收藏  举报