《P7167 [eJOI 2020] Fountain (Day1)》
题目描述
大家都知道喷泉吧?现在有一个喷泉由 N 个圆盘组成,从上到下以此编号为 1∼N,第 i 个喷泉的直径为 Di,容量为 Ci,当一个圆盘里的水大于了这个圆盘的容量,那么水就会溢出往下流,直到流入半径大于这个圆盘的圆盘里。如果下面没有满足要求的圆盘,水就会流到喷泉下的水池里。
现在给定 Q 组询问,每一组询问这么描述:
- 向第 Ri 个圆盘里倒入 Vi 的水,求水最后会流到哪一个圆盘停止。
 
如果最终流入了水池里,那么输出 0。
注意,每个询问互不影响。
输入格式
第一行两个整数 N,Q 代表圆盘数和询问数。
 接下来 N 行每行两个整数 Di,Ci 代表一个圆盘。
 接下来 Q 行每行两个整数 Ri,Vi 代表一个询问。
输出格式
Q 行每行一个整数代表询问的答案。
输入输出样例
输入 #1复制
6 5 4 10 6 8 3 5 4 14 10 9 4 20 1 25 6 30 5 8 3 13 2 8
输出 #1复制
5 0 5 4 2
说明/提示
样例 1 解释
前两个询问的解释如下图所示:

因为每个询问互不影响,对于第三个询问,第 5 个圆盘里的水不会溢出。
数据规模与约定
本题采用捆绑测试。
- Subtask 1(30 pts):N≤1000,Q≤2000。
 - Subtask 2(30 pts):Di 为严格单调递增序列。
 - Subtask 3(40 pts):无特殊限制。
 
对于 100% 的数据:
- 2≤N≤105。
 - 1≤Q≤2×105。
 - 1≤Ci≤1000。
 - 1≤Di,Vi≤109。
 - 1≤Ri≤N。
 
说明
翻译自 eJOI 2020 Day1 A Fountain。
代码实现1:
#include <iostream>
 #include <vector>  
 using namespace std;
 vector<int> a;
 vector<int> b;
 vector<int> c;
 vector<int> d;
 int search(vector<int> a,vector<int> b,vector<int> c,int k1,int k2,int n )
 {   int sum=0;
      int flag=0;
      int r=0;
      int k=0;
    for(int i=0;i<n;i++)
    {
        if(c[i]==k1)
        {
            k2-=b[i];
            r=a[i];
            flag=1;
        } 
        if(flag==1 && a[i]>r)
        {
            k2-=b[i];
            r=a[i];
        }
        if(k2<=0)
        {
            k=c[i];
            break;
        }
        //cout<<sum<<endl;
    }
     return k;
 }
 int main() {
     int n,m;
     cin>>n>>m;
     for(int i=0;i<n;i++)
     {
         int x,y;
         cin>>x>>y;
         a.push_back(x);
         b.push_back(y);
         c.push_back(i+1);
     }
     while(m)
     {   int k1,k2;
         cin>>k1>>k2;
        int mm=search(a,b,c,k1,k2,n);
        d.push_back(mm);
         m--;
     }
      for (int i = 0; i < d.size(); ++i) {
     cout << d[i] << endl;  // 使用d[i]访问元素
 }
     return 0;
 }
代码实现·2:
#include<bits/stdc++.h>
 using namespace std;
 #define re register
 #define maxn 100010
 #define inf 0x7f7f7f7f
 #define int long long
 #define Orz cout<<"stO %王队% Orz"<'\n';
 int n,q;
 struct node
 {
     int d,c;
 }a[maxn];
 int s[maxn],size;
 int f[maxn][25],u[maxn][25];
 inline int read(){
     int x=0,f=1;char ch=getchar();
     while (ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();}
     while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
     return x*f;
 }
 signed main()
 {
     cin>>n>>q;
     for(re int i=1;i<=n;++i)
         a[i].d=read(),a[i].c=read();//读入数据
     for(re int i=n;i>=1;--i)
     {
         while(size&&a[s[size]].d<=a[i].d)    size--;
         f[i][0]=s[size];
         s[++size]=i;
     }    //单调栈
     for(re int i=1;i<=23;++i)
         for(re int j=1;j<=n;++j)
             f[j][i]=f[f[j][i-1]][i-1];
     for(re int i=1;i<=n;++i)    
         u[i][0]=a[f[i][0]].c;
     for(re int i=1;i<=n;++i)
         if(f[i][0]==0)    
             u[i][0]=inf; //初始化u数组 
     for(re int i=1;i<=23;++i)
         for(re int j=1;j<=n;++j)
             u[j][i]=u[j][i-1]+u[f[j][i-1]][i-1];//倍增
     while(q--)
     {
         int r=read(),v=read();
         if(v<=a[r].c)
         {
             cout<<r<<'\n';
             continue;
         }
         v-=a[r].c;
         for(re int i=23;i>=0;--i)
             if(u[r][i]<=v)    
                 v-=u[r][i],r=f[r][i];
         if(v)    r=f[r][0];
         cout<<r<<'\n';
     }//回答询问
     return 0;
 }
