思路
先用单调栈找到比每个点大的第一个半径的下标,采用倍增的思想,记录每个点跳2的j次方步可以到达的点,用u[i][j]表示从i开始跳2的j次方步可以到达的位置,f[i][j]表示从i开始跳2的j次方步过程中容积的总和。
在这里插入代码片#include<bits/stdc++.h>
using namespace std;
int n,q;
const int N=1e5+10;
int u[N][20],f[N][20],d[N],c[N];//u表示从该点开始跳2的j次方步能跳到哪个点
//f表示从u开始跳2的j次方步,容量的总和是多少,d表示半径,c表示容量
int main()
{
stack<int>sk;//找到第一个比当前半径大的那个编号
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&d[i],&c[i]);
while(!sk.empty()&&d[sk.top()]<d[i])//当sk不空并且当前半径大于队头半径时,队头跳1步即可到达i
{
u[sk.top()][0]=i;
sk.pop();
}
sk.push(i);
}
for(int i=1;i<=n;i++)f[i][0]=c[i];
for(int j=1;1<<(j-1)<=n;j++)//跳2的j次方步
{
for(int i=1;i<=n;i++)//每个点都跳
{
u[i][j]=u[u[i][j-1]][j-1];//从i跳j次方步等于从i跳j-1次方步再跳j-1次方步
f[i][j]=f[i][j-1]+f[u[i][j-1]][j-1];//从i开始跳j次方步容量的总和等于从i开始跳j-1次方步的和加上从i开始跳j-1次方步到达的点跳j-1次方步容量的总和
}
}
int id,sum;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&id,&sum);
int lg=log2(n);//最多跳几步
for(int j=lg+1;j>=0;j--)
{
if(sum>f[id][j])
{
sum-=f[id][j];
id=u[id][j];
}
}
printf("%d\n",id);
}
return 0;
}