hihocoder 1488 排队接水

题目

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

有n个小朋友需要接水,其中第i个小朋友接水需要ai分钟。

由于水龙头有限,小Hi需要知道如果为第l个到第r个小朋友分配一个水龙头,如何安排他们的接水顺序才能使得他们等待加接水的时间总和最小。

小Hi总共会有m次询问,你能帮助他解决这个问题吗?

假设3个小朋友接水的时间分别是2,3,4。如果他们依次接水,第一位小朋友等待加接水的时间是2,第二位小朋友是5,第三位小朋友是9。时间总和是16。

输入

第一行一个数T(T<=10),表示数据组数
对于每一组数据:
第一行两个数n,m(1<=n,m<=20,000)
第二行n个数a1...an,表示每个小朋友接水所需时间(ai<=20,000)
接下来m行,每行两个数l和r

输出

对于每次询问,输出一行一个整数,表示答案。

样例输入

1
4 2
1 2 3 4
1 2
2 4

样例输出

4
16

分析

  • 离线算法——莫队算法 O(n1.5logn);
  • 已知查询(l,r),用平衡树维护区间数据,可以O(logn)求解(l-1,r)、(l+1,r)、(l,r-1)、(l,r+1);
  • sqrt(n)分块,左端点在同一块中的查询为一组,组内按右端点排序,调节左右端点即可;
  • 平衡树难写,每个排队时间不超过2e4,可以映射到数组,转换成数组区间求和,这里用树状数组;

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef uint8_t byte;
typedef int64_t illong;
typedef uint64_t ullong;
typedef uint32_t uint;
#define CLEAN(x) memset(x,0,sizeof(x))
#define TR(i,obj) for(__typeof(obj.begin()) i=obj.begin();i!=obj.end();++i)

struct Node{
    int l,r,ind;
    void set(int l,int r,int ind){
        this->l=l;
        this->r=r;
        this->ind=ind;
    }
    bool operator<(const Node &other)const;
};

const int tsize=1<<15;
int t,n,m,bsize;
int dat[tsize];
Node query[tsize];
illong cur,cl,cr;
illong dst[tsize];

bool Node::operator <(const Node &other)const{
    int sb=l/bsize;
    int ob=other.l/bsize;
    if(sb!=ob) return sbit.l)
                add(--cl);
            while(crit.r)
                rm(cr--);
            dst[it.ind]=cur;
        }
        for(int i=0;i

你可能感兴趣的:(hihocoder 1488 排队接水)