题目描述
原题来自:Vijos P1448
校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两种操作:
- K=1,读入 l,r表示在 l 到 r 之间种上一种树,每次操作种的树的种类都不同;
- K=2,读入 l,r表示询问 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% 的数据,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,1≤m≤5×104;
对于 100%100\%100% 的数据,1≤n,m≤5×1041\le n,m\le 5\times 10^41≤n,m≤5×104,保证 l,r>0l,r\gt 0l,r>0。