题目
试题编号 | 202203-2 |
---|---|
试题名称 | 出行计划 |
时间限制 | 1.5s |
内存限制 | 512MB |
问题描述 | |
输入输出 | |
样例1 | |
样例说明 |
题目分析
如果你暴力去做,即在每次输入q时判断:
q
+
k
≤
t
i
<
q
+
k
+
c
i
(
i
∈
[
1
,
n
]
)
q+k\leq t_i < q+k+c_i (i\in[1,n])
q+k≤ti<q+k+ci(i∈[1,n])
这样肯定会超时,因为n和m的规模都在
1
0
5
10^5
105,要求解
1
0
10
10^{10}
1010太慢了。
换个思路,把上面的等式变换一下,针对于每个活动i,可以计算出活动i的合法时间
q
q
q:
t
i
−
k
−
c
i
<
q
i
≤
t
i
−
k
t_i-k-c_i <q_i\leq t_i-k
ti−k−ci<qi≤ti−k也就是说对于每一个活动i,有一个合法时间区间
[
t
i
−
k
−
c
i
+
1
,
t
i
−
k
]
[t_i-k-c_i+1,t_i-k]
[ti−k−ci+1,ti−k]是可以满足题意的。
- 先建立一个表示时间轴的数组c[200005]。初始化为0.
- 对于每一个活动 ( t i , c i ) (t_i,c_i) (ti,ci),将 [ t i − k − c i + 1 , t i − k ] [t_i-k-c_i+1,t_i-k] [ti−k−ci+1,ti−k]在c数组中+1。表示该时间点是可满足活动i的。
- 在m个查询q的时候,直接访问c[q]就可以了,c[q]的值表示的就是可满足的活动数量。
分析
- 要注意 [ t i − k − c i + 1 , t i − k ] [t_i-k-c_i+1,t_i-k] [ti−k−ci+1,ti−k]更新区间要在大于等于1的时间下进行。
- 算法优化:要知道每次更新长度为
[
t
i
−
k
−
c
i
+
1
,
t
i
−
k
]
[t_i-k-c_i+1,t_i-k]
[ti−k−ci+1,ti−k]的数组,执行n个活动是可以满足题意的,但是还是太慢了!!!一个好的算法怎么容忍这种线性时间的更新呢?所以总结下我们的方法的特征。
(1) 区间更新 (2)定点查询
你想到了什么?没错!线段树或者BIT。我用的是BIT可以达到:
60ms即可解决。一般来说BIT是定点更新区间查找。改一下就行了。让 s u m ( n ) = ∑ 1 n ( t [ i ] − t [ i − 1 ] ) = t [ n ] sum(n)=\sum_1^n(t[i]-t[i-1])=t[n] sum(n)=1∑n(t[i]−t[i−1])=t[n]区间[l,r]更新的时候只需要更新 u p d a t e ( l , 1 ) , u p d a t e ( r + 1 , − 1 ) update(l,1),update(r+1,-1) update(l,1),update(r+1,−1)注意到区别,原来的BIT每个c[i]存储的是a[i],现在是存储a[i]-a[i-1],差分的思想,需要了解一下。
AC代码
#include <stdio.h>
#include <string.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
#define mem(a) memset(a,0,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int c[200005];
int _n,m,k,t,cc,ans,l,r,q;
const int n=200005;
int lowbit(int i){
return i&(-i);
}
void update(int i,int x){
while(i<=n){
c[i]+=x;
i+=lowbit(i);
}
}
int sum(int i){
int ans=0;
while(i>0){
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
int main(){
mem(c);
scanf("%d%d%d",&_n,&m,&k);
rep(i,1,_n+1){
scanf("%d%d",&t,&cc);
l=t-k-cc;
r=t-k;//[l+1,r]
if(l+1>=1){
update(l+1,1);
update(r+1,-1);
}
else if(l+1<1&&r>=1){
update(1,1);
update(r+1,-1);
}
}
while(m--){
scanf("%d",&q);
printf("%d\n",sum(q));
}
return 0;
}
/*
6 2 10
5 24
10 24
11 24
34 24
35 24
35 48
1
2
*/