noip模拟赛 蒜头君的排序_#include

noip模拟赛 蒜头君的排序_编程题_02

noip模拟赛 蒜头君的排序_编程题_03

分析:其实就是求m个区间的逆序对个数,题目真的是明摆着让我们用莫队算法,套用树状数组就可以了.

具体怎么转移呢?如果移动R,那么对区间[l,r]有影响的是R左边的元素,我们只需要看有多少在R左边比a[R]大的元素就可以了.如果移动L,对[l,r]有影响的是L右边的元素,并且比a[L]小,我们在移动L的时候看看有多少比a[L]小就可以了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int n,a[30010],m,sizee,L = 1,R = 0,ans,c[300010],sum[30010];

struct node
{
    int l, r, id;
}e[30010];

int query(int x)
{
    int res = 0;
    while (x)
    {
        res += c[x];
        x -= x & (-x);
    }
    return res;
}

void add(int x, int v)
{
    while (x <= n)
    {
        c[x] += v;
        x += x & (-x);
    }
}

bool cmp(node a, node b)
{
    if (a.l / sizee == b.l / sizee)
        return a.r < b.r;
    return a.l < b.l;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    sizee = sqrt(n);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%d", &e[i].l, &e[i].r);
        e[i].id = i;
    }
    sort(e + 1, e + 1 + m, cmp);
    for (int i = 1; i <= m; i++)
    {
        while (R < e[i].r)
        {
            ans += query(n) - query(a[++R] - 1);
            add(a[R], 1);
        }
        while (R > e[i].r)
        {
            add(a[R], -1);
            ans -= query(n) - query(a[R--] - 1);
        }
        while (L < e[i].l)
        {
            add(a[L], -1);
            ans -= query(a[L++] - 1);
        }
        while (L > e[i].l)
        {
            ans += query(a[--L] - 1);
            add(a[L], 1);
        }
        sum[e[i].id] = ans;
    }
    for (int i = 1; i <= m; i++)
        printf("%d\n", sum[i]);

    return 0;
}