P7424 [THUPC 2017] 天天爱射击
P7424 [THUPC 2017] 天天爱射击
题目描述
小 C 爱上了一款名字叫做《天天爱射击》的游戏。如图所示,这个游戏有一些平行于 \(x\) 轴的木板。现在有一些子弹,按顺序沿着 \(y\) 轴方向向这些木板射去。第 \(i\) 块木板被 \(S_i\) 个子弹贯穿以后,就会碎掉消失。一个子弹可以贯穿其弹道上的全部木板,特别的,如果一个子弹触碰到木板的边缘,也视为贯穿木板。
小 C 现在知道了游戏中 \(n\) 块木板位置,以及知道了 \(m\) 个子弹射击位置。现在问你每个子弹射出去以后,有多少木板会碎掉?
输入格式
从标准输入读入数据。
第一行两个整数 \(n\) 和 \(m\),表示木板数量和子弹数量。其中 \(1\le n,m\le 2\times 10^5\)。
接下来 \(n\) 行,每行三个整数 \(x_1,x_2,s\),表示每块木板的左端点 \(x\) 坐标、右端点 \(x\) 坐标,以及贯穿多少次会碎掉。其中保证 \(1\le x_1\le x_2\le2\times 10^5,1\le s\le 2\times 10^5\)。
接下来 \(m\) 行,每行一个整数 ,表示每个子弹的 \(x\) 坐标。子弹按照发射顺序给出。其中保证 \(1\le x\le2\times 10^5\)。
输出格式
输出到标准输出。
\(m\) 行,每行一个整数。表示每颗子弹射出去后,有多少木板碎掉。
输入输出样例 #1
输入 #1
3 2
1 3 1
2 4 2
3 4 1
2
3
输出 #1
1
2
说明/提示

版权信息
来自 THUPC(THU Programming Contest,清华大学程序设计竞赛)2017。
Solution:
我们思维转化一下,由于每个木板最多只产生 1 的贡献,所以我们可以针对每个木板什么时候断来进行讨论。
我们用线段树来维护子弹的位置,我们在一个二位平面内将 \(x\) 轴定义为子弹射出的位置 \(y\) 轴定义为子弹射出的时间。那么我们查询一块木板 \((l,r,s)\) 什么时候断,只需要查询 \((l,1)\ ,\ (r,inf)\) 矩形内的 \(y\) 坐标第 \(s\) 小点就好了。然后按照这个时间对应回子弹的编号,然后这题就做完了。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct Tree{
int ls,rs,v;
}t[N*30];
struct kkk{
int l,r,w;
}q[N];
vector<int> shoot[N];
int n,m,cnt;
int rt[N],ans[N];
void upd(int &x,int l,int r,int k)
{
t[++cnt]=t[x];t[x=cnt].v++;if(l==r)return ;
int mid=l+r>>1;
if(k<=mid)upd(t[x].ls,l,mid,k);
else upd(t[x].rs,mid+1,r,k);
}
int query(int lx,int rx,int l,int r,int k)
{
int num=t[t[rx].ls].v-t[t[lx].ls].v;
if(l==r)return l;
int mid=l+r>>1;
if(k<=num) return query(t[lx].ls,t[rx].ls,l,mid,k);
else return query(t[lx].rs,t[rx].rs,mid+1,r,k-num);
}
int main()
{
//freopen("P7424.in","r",stdin);
//freopen("P7424.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].w);
}
for(int i=1,x;i<=m;i++)
{
scanf("%d",&x);
shoot[x].push_back(i);
}
for(int i=1;i<=2e5;i++)
{
if(!shoot[i].size())shoot[i].push_back(m+1);
}
for(int i=1;i<=2e5;i++)
{
rt[i]=rt[i-1];
for(int j=0;j<=shoot[i].size()-1;j++)
{
upd(rt[i],1,m+1,shoot[i][j]);
}
}
for(int i=1;i<=n;i++)
{
int res=query(rt[q[i].l-1],rt[q[i].r],1,m+1,q[i].w);
//cout<<res<<"\n";
if(res!=m+1)ans[res]++;
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}

浙公网安备 33010602011771号