现在的位置: 首页 > 综合 > 正文

BZOJ 3744 Gty的妹子序列 分块+fenwick

2017年11月21日 ⁄ 综合 ⁄ 共 2430字 ⁄ 字号 评论关闭

题目大意:强制在线区间无修改逆序对。

思路:看到数据范围发现分块是很显然的。预处理了很多东西,比如说每个块里面的逆序对个数,还有f[i][j]表示从第i块到第j块的逆序对个数。如果仅仅处理到这里的话,后面是不太好处理的。我们还需要一个东西,是每个点对每个块的逆序对个数,并取前缀合优化。否则的话就得用主席树来乱搞,那常数

反正总时间复杂度大概是O(n*sqrt(n)*logn)  强行不到O(n^2)

剩下就是小事了, 比如离散话啥的。。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 400
#define RANGE 50010
using namespace std;
#define max(a,b) ((a) > (b) ? (a):(b))
 
struct Block{
    int num[MAX],total;
     
    void Add(int x) {
        num[++total] = x;
    }
}block[MAX];
 
int cnt,size,blocks,asks;
pair<int,int *> xx[RANGE];
int src[RANGE],t;
int belong[RANGE],_begin[MAX],_end[MAX];
 
int fenwick[RANGE],v[RANGE],T;
int ans[MAX][MAX],g[RANGE][MAX];
 
inline void Fix(int x)
{
    for(; x; x -= x&-x) {
        if(v[x] != T)   v[x] = T,fenwick[x] = 0;
        ++fenwick[x];
    }
}
 
inline int GetSum(int x)
{
    int re = 0;
    for(; x <= t; x += x&-x) {
        if(v[x] != T)   v[x] = T,fenwick[x] = 0;
        re += fenwick[x];
    }
    return re;
}
 
int temp[RANGE];
 
inline int Calc(int total)
{
    ++T;
    int re = 0;
    for(int i = 1; i <= total; ++i) {
        re += GetSum(temp[i] + 1);
        Fix(temp[i]);
    }
    return re;
}
 
int main()
{
    cin >> cnt;
    size = sqrt(cnt);
    for(int i = 1; i <= cnt; ++i) {
        scanf("%d",&xx[i].first);
        xx[i].second = &src[i];
    }
    sort(xx + 1,xx + cnt + 1);
    for(int i = 1; i <= cnt; ++i) {
        if(i == 1 || xx[i].first != xx[i - 1].first)
            ++t;
        *xx[i].second = t;
    }
    for(int i = 1; i <= cnt; ++i) {
        belong[i] = i / size + 1;
        blocks = max(blocks,belong[i]);
        if(!_begin[belong[i]])          _begin[belong[i]] = i;
        if(belong[i] != belong[i - 1])  _end[belong[i] - 1] = i - 1;
    }
    _end[blocks] = cnt;
    for(int i = 1; i <= cnt; ++i)
        block[belong[i]].Add(src[i]);
     
    for(int i = 1; i <= blocks; ++i) {
        ++T;
        int inv = 0;
        for(int j = i; j <= blocks; ++j) {
            for(int k = 1; k <= block[j].total; ++k) {
                inv += GetSum(block[j].num[k] + 1);
                Fix(block[j].num[k]);
            }
            ans[i][j] = inv;
        }
    }
     
    for(int i = 1; i <= blocks; ++i)
        sort(block[i].num + 1,block[i].num + block[i].total + 1);
     
    for(int i = 1; i <= cnt; ++i) {
        for(int j = 1; j < belong[i]; ++j)
            g[i][j] = g[i][j - 1] + (block[j].total - (upper_bound(block[j].num + 1,block[j].num + block[j].total + 1,src[i]) - block[j].num) + 1);
        for(int j = belong[i] + 1; j <= blocks; ++j)
            g[i][j] = g[i][j - 1] + (lower_bound(block[j].num + 1,block[j].num + block[j].total + 1,src[i]) - block[j].num - 1);
    }
     
    int last_ans = 0;
    cin >> asks;
    for(int x,y,i = 1; i <= asks; ++i) {
        scanf("%d%d",&x,&y);
        x ^= last_ans,y ^= last_ans;
        if(x > y)   swap(x,y);
        if(belong[x] == belong[y] || belong[x] == belong[y] - 1) {
            int top = 0;
            for(int j = x; j <= y; ++j)
                temp[++top] = src[j];
            printf("%d\n",last_ans = Calc(top));
            continue;
        }
        int l = belong[x] + 1,r = belong[y] - 1;
        int out = ans[l][r],top = 0;
        for(int j = x; j <= _end[belong[x]]; ++j) {
            out += g[j][r] - g[x][l - 1];
            temp[++top] = src[j];
        }
        for(int j = _begin[belong[y]]; j <= y; ++j) {
            out += g[j][r] - g[j][l - 1];
            temp[++top] = src[j];
        }
        out += Calc(top);
        printf("%d\n",last_ans = out);
    }
    return 0;
}

抱歉!评论已关闭.