原題連接:http://acm.hdu.edu.cn/showproblem.php?pid=4325
題意:給n朵花,每朵花都有一個開花時間(是一個區間),給q次查詢命令,每次查詢輸入一個時間點,詢問該時刻共有多少花正在開……
思路:這就是一個樹狀數組的 插線問點 算法,但是 注意 範圍1 <= Si <= Ti <= 10^9 數組是開不下的,而且n,q 的範圍比較小,這就說明要先對數據進行離散化處理,縮小範圍即可。。但是怎麼離散化呢?首先我們 看題,查詢是離線的,我們可以將開花的時間區間和查詢一次全部離散化了,這樣就不影響最終結果了。
首先我們在輸入每組數據是要記錄編號,記錄在flo 中(即輸入順序) -----參考代碼 P1 處
然後我們根據num 值的大小對結構體排序
接着我們通過訪問編號將num值離散化,注意可能有重複的num,保存在 AC[i]=j數組中,i是輸入時的編號,j是離散後的數值。 ------P2
最後通過編號在樹狀數組ans中插線,然後問點。-----P3
AC代碼:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int Max=110000;
int AC[Max],ans[Max];
struct hello
{
int num;
int id;
}flo[Max];
int lowbit(int i)
{
return i&(-i);
}
void update(int x,int y)
{
while(x<Max)
{
ans[x]+=y;
x+=lowbit(x);
}
}
int find(int x)
{
int sum=0;
while(x>0)
{
sum+=ans[x];
x-=lowbit(x);
}
return sum;
}
bool cmp(hello t1,hello t2)
{
return t1.num<t2.num;
}
int main()
{
int i,j,n,m,ncase,q;
scanf("%d",&ncase);
for(m=1;m<=ncase;m++)
{
int s,t,cnt=0;
printf("Case #%d:\n",m);
memset(ans,0,sizeof(ans));
memset(AC,0,sizeof(AC));
scanf("%d%d",&n,&q);
for(i=0;i<2*n+q;i++)
{
scanf("%d",&flo[i].num); //------P1
flo[i].id=i;
}
sort(flo,flo+2*n+q,cmp);
for(i=0;i<2*n+q;i++)
{
if(i==0||flo[i].num!=flo[i-1].num) //--------P2
AC[flo[i].id]=++cnt;
else
AC[flo[i].id]=cnt;
}
for(i=0;i<2*n;i+=2) //--------P3
{
update(AC[i],1);
update(AC[i+1]+1,-1);
}
for(i=2*n;i<2*n+q;i++)
printf("%d\n",find(AC[i]));
}
}