解题思路
我们发现直接做不是很好做
考虑计算每个木板是在第几次射击被射掉的
这显然是具有可二分性的
于是我们考虑整体二分
每次二分中间点
m
i
d
mid
mid,然后将时间小于等于mid的射击,在它的那个位置上加一
然后枚举木板的时候,就看这块木板能覆盖的范围内有多少个1,就可以知道
m
i
d
mid
mid对于这个木板是大了,还是小了
单点加,区间查询,可以用树状数组维护
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
struct node
{
int t,l,r,s,id;
}q[2*N],tmp1[2*N],tmp2[2*N];
int tot=0;
void Add(int t,int l,int r,int s,int id)
{
tot++;
q[tot]=(node){t,l,r,s,id};
}
int n,m,R;
int tree[N];
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int v)
{
for(int i=x;i<=R;i+=lowbit(i))
tree[i]+=v;
}
int ask(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=tree[i];
return res;
}
int Ans[N];
void solve(int ql,int qr,int l,int r)
{
if(l==r)
{
for(int i=ql;i<=qr;i++)
if(q[i].t==2) Ans[q[i].id]=l;
return;
}
int mid=(l+r)>>1;
int top1=0,top2=0;
for(int i=ql;i<=qr;i++)
{
if(q[i].t==1)
{
if(q[i].id<=mid)
{
add(q[i].l,1);
tmp1[++top1]=q[i];
}
else tmp2[++top2]=q[i];
}
else
{
int cnt=ask(q[i].r)-ask(q[i].l-1);
if(cnt>=q[i].s) tmp1[++top1]=q[i];
else
{
q[i].s-=cnt;
tmp2[++top2]=q[i];
}
}
}
for(int i=1;i<=top1;i++)
if(tmp1[i].t==1) add(tmp1[i].l,-1);
for(int i=1;i<=top1;i++) q[ql+i-1]=tmp1[i];
for(int i=1;i<=top2;i++) q[ql+top1+i-1]=tmp2[i];
solve(ql,ql+top1-1,l,mid);
solve(ql+top1,qr,mid+1,r);
}
bool cmp(node a,node b)
{
return a.t<b.t;
}
int sum[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int l,r,s;
scanf("%d %d %d",&l,&r,&s);
R=max(R,r);
Add(2,l,r,s,i);
}
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
R=max(R,x);
Add(1,x,x,0,i);
}
sort(q+1,q+tot+1,cmp);
solve(1,tot,1,m+1);
for(int i=1;i<=n;i++)
sum[Ans[i]]++;
for(int i=1;i<=m;i++)
printf("%d\n",sum[i]);
return 0;
}