hihocode 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


题目链接:http://hihocoder.com/problemset/problem/1488


思路:多区间的问题莫队算法是很好的解决方式,通过排序,使得区间增加减少的最少,然后只需要求出[l,r]转移到[l+1,r],[l-1,r],[l,r-1],[l,r+1],四个转移方程式即可在nsqrt(n)的时间复杂度求出所有的查询区间。

   此题中新加入一个数,我们只需要求出小于等于此数的和和大于此数的个数即可算出这个数加进去之后对答案的贡献度。


代码:

#include

using namespace std;

typedef long long ll;
const int MAXN=100000+5;

int a[MAXN];
int cnt[1<<20];
ll result;
ll ans[MAXN],bit1[MAXN],bit2[MAXN];
int unit,n,m,k;

struct Query
{
    int L,R,id;
} query[MAXN];

bool cmp( Query a,Query b )
{
    if( a.L/unit==b.L/unit )return a.Rquery[i].R )
        {
            int x=sum(a[R]);
            int w=sum2(a[R]);
            result-=w+(R-L+1-x)*a[R];
            add(a[R],-1);
            add2(a[R],-a[R]);
            R--;
        }
        while( L>query[i].L )
        {
            L--;
            int x=sum(a[L]);
            int w=sum2(a[L]);
            result+=w+(R-L+1-x)*a[L];
            add(a[L],1);
            add2(a[L],a[L]);
        }
        while( L



你可能感兴趣的:(hihocode 1488 排队接水(莫队算法))