这题一看就是区间更新单点查询,比较裸的线段树……当时敲的时候手残了,没敲好,后来队友用树状数组过的……今天我也写了一个树状数组,不过不知道为什么效率不佳,得300+ms才过,可能我离散化写的有问题,写了两个版本的,一个是用stl的,一个没有……离散化我一直都不是太清楚怎么写,自己yy了一个…………
这题用树状数组写的时候其实是树状数组反过来用,sum(x)表示查询x处话的数量,而更新区间则是用两次add
如,我要在区间(2,5)加1,那么我add(2,1)在2的地方加一个1,这时sum(大于等于2)的数都增加了1,那么只要再add(6,-1),这时sum(大于等于6)的数都少了1,等于之前的1白加,而这时,2到5之间那个加的1还是在的,所以这样就满足了(2,5)区间的数加了1
离散化写的很挫…………希望读者能够指点迷津
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 100010;
struct point
{
int x;
int flag;
int id;
}p[MAX<<2];
int cmp(const point &a,const point &b)
{
return a.x<b.x;
}
int lowbit(int p)
{
return p&(-p);
}
int cnt;
int a[MAX<<2];
void plus(int x,int c)
{
while(x<=cnt)
{
a[x]+=c;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans = 0;
while(x)
{
ans+=a[x];
x-=lowbit(x);
}
return ans;
}
int x[3][MAX];
int main()
{
int cas;
scanf("%d",&cas);
for(int t=1; t<=cas; t++)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0; i<n*2; i+=2)
{
scanf("%d%d",&p[i].x,&p[i+1].x);
p[i].flag = 0;
p[i+1].flag = 1;
p[i].id = p[i+1].id = i/2;
}
for(int i=2*n; i<2*n+m; i++)
{
scanf("%d",&p[i].x);
p[i].flag = 2;
p[i].id = i - 2 * n;
}
sort(p,p+2*n+m,cmp);
cnt = 0;
int now = -1;
for(int i=0; i<2*n+m; i++)
{
if(now!=p[i].x)
{
cnt++;
now = p[i].x;
}
x[p[i].flag][p[i].id] = cnt;
}
memset(a,0,sizeof(a));
for(int i=0; i<n; i++)
{
plus(x[0][i],1);
plus(x[1][i]+1,-1);
}
printf("Case #%d:\n",t);
for(int i=0; i<m; i++)
printf("%d\n",sum(x[2][i]));
}
return 0;
}