分块对于区间操作复杂度为 sqrt(n);
最坏情况是 查询 1到 n
左端暴力sqrt(n) , 右端暴力sqrt(n), 中间还有sqrt(n)-2块 所以 最坏sqrt(3*n); //即最坏常数为3
/*************
分 块 将 n 个数 分为多个块 , 便于区间修改 和查找
如果 元素总个数 为 n
①每个块中元素的个数,用block表示 block = (int)sqrt(n); (注意 表示的 是每块的元素个数)
②块的个数,用num表示: num = n/block; if(n%block!= 0)num++; //整除不了要多加一块 个人认为还可以 n/block 向上取整
③地i个块的端点:
右端点: r[i] = i*block; //右端点好计算
左端点: l[i] = (i -1)*block;// 每个块的左端点 就等于前一个块的右端点+1
④元素所属于的块号:
belong[i] = (i-1)/block + 1;//
********************/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 1e5+50;
int n;
int num;
int block;
int l[maxn], r[maxn];
int belong[maxn];// 这几个元素是分块必备的
void build() // 建立 函数, 这个函数也是必备的
{
block = (int)sqrt(n);// 求 每个块中元素的个数
/* 求块的个数*/
num = n/block;
if(n%block!=0)num++;
/*求每个块的左右端点*/
for(int i = 1;i <= num;i++)
{
l[i] = (i-1)*block+1;
r[i] = i*block;
}
/*最后一个块的右端点*/
r[num] = n;
/*求每个元素所属的块*/
for(int i = 1;i <= n;i++)
{
belong[i] = (i-1)/block+1;
}
}
int arr[maxn];// 单个 累加
int add[maxn];// 区间累加
void update(int x, int y) // 这个函数也是分块必备的, 不同的题处理不同
{
if(belong[x] == belong[y])//x,y在一个块内直接暴力
{
for(int i = x;i<= y;i++)
{
arr[i]++;
}
return ;
}
else// 不在一个块内
{
//处理左边角
for(int i = x;i <= r[belong[x]];i++)
{
arr[i]++;
}
//处理右边角
for(int i = l[belong[y]];i <= y;i++)
{
arr[i]++;
}
//处理整个块
for(int i = belong[x]+1;i < belong[y];i++)
{
add[i]++;
}
}
}
int main()
{
while(~scanf("%d", &n)&& n)
{
memset(arr, 0, sizeof(arr)); // 初始化 原来数组
build();
memset(add, 0, sizeof(add));
for(int i = 0;i < n;i++)
{
int a, b;
scanf("%d %d", &a, &b);
update(a, b);
}
for(int i = 1;i <= n;i++)
{
if(i < n)printf("%d ", arr[i]+add[belong[i]]);
else printf("%d\n", arr[i]+add[belong[i]]);
}
}
return 0;
}