一看就是个裸线段树,而且每次更新就是区间内所有数+1。这题的难点在于它的范围,n<=10^9!!!肿么办?离散化!虽然数据规模灰常吓人,但与传统线段树题目相比可以找到一点区别,那就是有大量的无用节点。。。于是果断压缩,就用到了离散化。把所有的数据都存在一个数组中,而这个数组的容量就是线段树长度,将10^9压缩到30W。然后再借助二分查找,用线段树解决。。。。附代码:
#include <iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clear(a) memset(a,0,sizeof(a))
const int N=100100;
int sum[N<<5],col[N<<5],c[3*N],s1[N],s2[N],q[N];
int n,k;
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int l,int r,int rt)
{
int k,m;
if (col[rt])
{
k=col[rt];
m=(l+r)>>1;
sum[rt<<1]+=k*(m-l+1);
sum[rt<<1|1]+=k*(r-m);
col[rt<<1]+=k;
col[rt<<1|1]+=k;
col[rt]=0;
}
}
void update(int L,int R,int l,int r,int rt)
{
pushdown(l,r,rt);
if (L<=l&&r<=R)
{
sum[rt]+=(r-l+1);
col[rt]++;
return;
}
int m=(l+r)>>1;
if (L<=m) update(L,R,lson);
if (R>m) update(L,R,rson);
pushup(rt);
}
void query(int p,int l,int r,int rt)
{
pushdown(l,r,rt);
if (l==r)
{
printf("%d\n",sum[rt]);
return;
}
int m=(l+r)>>1;
if (p<=m) query(p,lson);
else query(p,rson);
}
int find(int x,int l,int r)
{
if (r-l<1)
{
if (c[l]==x) return l;
else return r;
}
int m=(l+r)>>1;
if (c[m]==x) return m;
else if (c[m]>x) return find(x,l,m-1);
else return find(x,m+1,r);
}
void deal(int m)
{
int i,a,b;
for (i=1;i<=n;i++)
{
a=find(s1[i],1,k);
b=find(s2[i],1,k);
update(a,b,1,k,1);
}
for (i=1;i<=m;i++)
{
a=find(q[i],1,k);
query(a,1,k,1);
}
return;
}
int main()
{
int T,i,j,x,m;
scanf("%d",&T);
for (j=1;j<=T;j++)
{
clear(s1);
clear(s2);
clear(q);
clear(c);
clear(sum);
clear(col);
scanf("%d%d",&n,&m);
k=0;
for (i=1;i<=n;i++)
{
scanf("%d%d",&s1[i],&s2[i]);
c[++k]=s1[i];
c[++k]=s2[i];
}
for (i=1;i<=m;i++)
{
scanf("%d",&q[i]);
c[++k]=q[i];
}
sort(c+1,c+k+1);
c[0]=-1;
x=0;
for (i=1;i<=k;i++)
if (c[i]!=c[i-1]) c[++x]=c[i];
k=x;
printf("Case #%d:\n",j);
deal(m);
}
return 0;
}