csuoj 2316 Joined Vessels

Description
John is doing physics practice at school. Today he is studying the law of communicating vessels. This law states that if we have a set of communicating containers with a homogeneous liquid, when the liquid settles, it balances out to the same level in all of the containers regardless of their shape and volume.

In the lab, John has a set of n cylindrical vessels with a base area of one square decimeter and a height that we consider to be infinite. The vessels are numbered from 1 to n, and vessels i and i + 1 are communicating via a very thin bridge at a height of hi decimeters. All these heights are pairwise distinct.

The practice work contains t independent experiments. In each experiment, all vessels are initially empty. In the i-th experiment, water is slowly put into vessel ai, and the experiment finishes when any amount of water appears in vessel bi. The result of the experiment is the total volume of water put into vessel ai, measured in liters (or, equivalently, cubic decimeters).

Note that the law of communicating vessels can only be applied to vessels i and i + 1 when the water level is at least hi in both of them. Until then, if the water level reaches hi in just one of them, it stays constant and any excess water coming into this vessel flows through the bridge into the other one.

Help John check his results!

Input
The first line of the input contains an integer n --- the number of vessels (2 ≤ n ≤ 2 ⋅ 105).

The second line contains n − 1 integers h1, h2, …, hn − 1 --- the heights of communication bridges between consecutive vessels, in decimeters (1 ≤ hi ≤ 109). These heights are pairwise distinct.

The third line contains an integer t --- the number of experiments (1 ≤ t ≤ 2 ⋅ 105).

Each of the following t lines contains two integers ai and bi --- the numbers of the starting vessel and the target vessel in the i-th experiment (1 ≤ ai ≤ n; 1 ≤ bi ≤ n; ai ≠ bi).

Output
For each experiment, in the order of input, output a single integer --- the required volume of water, in liters.

Sample Input
6
1 4 2 3 5
4
1 6
6 1
2 5
5 2
Sample Output
25
18
14
12

 

题意:n个桶,第i个桶和第i+1个桶有高度为hi的导管连通,m个询问,问将水不断导入桶a,要倒多少才会有水流入桶b。n,m<=2e5

分析:考虑a<b时的情况(a>b时逆序处理),每次将水倒入a,有水流入b时,则桶a到桶b-1的水平面呈阶梯形下降,且不管将水从a左边哪个桶倒入,桶a到桶b-1的水平高度都不会变。这样可以用前缀和,sum[i]表示从第一个桶开始倒水,水溢过第i根管子时需倒入的水量。同时还要考虑将水倒入a时,水往左流的情况,假设[a,b-1]导管的最大高度为max,则水会不断往左流直到遇到高度大于max的管子k,这样答案即为sum[b-1]-sum[k];

所以单调栈+RMQ。。。。

 

 

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
int st[200010],l1[200010],l2[200010];
long long sum1[200010],sum2[200010],A[2][200010],ma[2][1000010];

void update(int root,int l,int r,int k,int v,int id){
     if(l==r) ma[id][root]=l;
     else{
         int mid=(l+r)/2;
         if(k>mid) update(root*2+1,mid+1,r,k,v,id);
         else update(root*2,l,mid,k,v,id);
         if(A[id][ma[id][root*2]]>=A[id][ma[id][root*2+1]]) ma[id][root]=ma[id][root*2];
         else ma[id][root]=ma[id][root*2+1];
     }
}
int qmax(int root,int l,int r,int L,int R,int id){
     if(l==L&&r==R) return ma[id][root];
     int mid=(l+r)/2;
     if(R<=mid) return qmax(root*2,l,mid,L,R,id);
     else if(L>mid) return qmax(root*2+1,mid+1,r,L,R,id);
     else{
         int a=qmax(root*2,l,mid,L,mid,id),b=qmax(root*2+1,mid+1,r,mid+1,R,id);
         if(A[id][a]>=A[id][b]) return a;
         else return b;
     }
}


int main(){
    int a,b,c,d,m,i,n,top;
    scanf("%d",&n);
    for(i=1;i<n;i++){
        scanf("%lld",&A[0][i]);
        A[1][n-i]=A[0][i];    //逆序处理
    }
    for(i=1;i<n;i++){
        update(1,1,n-1,i,A[0][i],0);
        update(1,1,n-1,i,A[1][i],1);
    }
        
    top=0;          //单调栈处理左边第一个大于它的数
    for(i=1;i<n;i++){
        while(top&&A[0][st[top]]<=A[0][i]) top--;
        if(top) l1[i]=st[top];
        else l1[i]=0;
        st[++top]=i;
    }
    for(i=1;i<n;i++) sum1[i]=sum1[l1[i]]+(i-l1[i])*A[0][i];

    top=0;
    for(i=1;i<n;i++){
        while(top&&A[1][st[top]]<=A[1][i]) top--;
        if(top) l2[i]=st[top];
        else l2[i]=0;
        st[++top]=i;
    }
    for(i=1;i<n;i++) sum2[i]=sum2[l2[i]]+(i-l2[i])*A[1][i];

    long long ans;
    scanf("%d",&m);
    while(m--){
        scanf("%d%d",&a,&b);
        if(a<b){
             b--;
             c=qmax(1,1,n-1,a,b,0);
             ans=sum1[b]-sum1[l1[c]];
        }
        else{
            a=n-a+1;
            b=n-b+1;
            b--;
            c=qmax(1,1,n-1,a,b,1);
            ans=sum2[b]-sum2[l2[c]];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值