zoukankan      html  css  js  c++  java
  • BZOJ 3289: Mato的文件管理 【莫队 + 树状数组】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3289

    3289: Mato的文件管理

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 4917  Solved: 2041
    [Submit][Status][Discuss]

    Description

    Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号
    。为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问。Mato每天随机选一个区间[l,r
    ],他今天就看编号在此区间内的这些资料。Mato有一个习惯,他总是从文件大小从小到大看资料。他先把要看的
    文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。排序程序可以在1单位时间内交换2个相邻的
    文件(因为加密需要,不能随机访问)。Mato想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?

    Input

    第一行一个正整数n,表示Mato的资料份数。
    第二行由空格隔开的n个正整数,第i个表示编号为i的资料的大小。
    第三行一个正整数q,表示Mato会看几天资料。
    之后q行每行两个正整数l、r,表示Mato这天看[l,r]区间的文件。
    n,q <= 50000

    Output

    q行,每行一个正整数,表示Mato这天需要交换的次数。

    Sample Input

    4
    1 4 2 3
    2
    1 2
    2 4

    Sample Output

    0
    2
    //样例解释:第一天,Mato不需要交换
    第二天,Mato可以把2号交换2次移到最后。

    题意概括:

    其实就是查询区间的逆序数。

     

    解题思路:

    首先根据数据范围,可以先对数据进行离散化。

    用树状数组维护当前区间出现的数,那么 X 的逆序数就是在 X 之前已存在当前区间的比 X 大的数,通过树状数组这个很容易实现,然后通过莫队离线操作进行区间的转移。

    AC code:

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 #define LL long long
     4 using namespace std;
     5 const int MAXN = 5e4+10;
     6 
     7 int N, M;
     8 struct Query
     9 {
    10     int l, r, idx;
    11 }Q[MAXN];
    12 int unit;
    13 int a[MAXN], b[MAXN], ans[MAXN];
    14 int t[MAXN];
    15 int lowbit(int x){return x&(-x);}
    16 bool cmp(struct Query a, struct Query b)
    17 {
    18     int la = a.l/unit, lb = b.l/unit;
    19     if(la == lb) return a.r < b.r;
    20     return la < lb;
    21 }
    22 
    23 void add(int x, int val)
    24 {
    25     for(int i = x; i < MAXN; i+=lowbit(i))
    26         t[i] += val;
    27 }
    28 
    29 int ask(int x)
    30 {
    31     int res = 0;
    32     for(int i = x; i; i-=lowbit(i))
    33         res+=t[i];
    34     return res;
    35 }
    36 
    37 void solve()
    38 {
    39     int L = 1, R = 0, cur = 0;
    40     for(int i = 1; i <= M; i++){
    41         while(L < Q[i].l) {cur-=ask(a[L]-1); add(a[L], -1);L++;}
    42         while(L > Q[i].l) {cur+=ask(a[L-1] - 1); add(a[L-1], 1); L--;}
    43         while(R < Q[i].r) {cur+=R-L+1-ask(a[R+1]); add(a[R+1], 1); R++;}
    44         while(R > Q[i].r) {cur-=R-L+1-ask(a[R]); add(a[R], -1); R--;}
    45         ans[Q[i].idx] = cur;
    46     }
    47 
    48     for(int i = 1; i <= M; i++){
    49         printf("%d
    ", ans[i]);
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     scanf("%d", &N);
    56     unit = sqrt(N);
    57     for(int i = 1; i <= N; i++){ scanf("%d", &a[i]); b[i] = a[i];}
    58     scanf("%d", &M);
    59     for(int i = 1; i <= M; i++){
    60         scanf("%d %d", &Q[i].l, &Q[i].r);
    61         Q[i].idx = i;
    62     }
    63     sort(b+1, b+N+1);                   //离散化
    64     int cnt = unique(b+1, b+1+N)-b-1;
    65     for(int i = 1; i <= N; i++){
    66         a[i] = lower_bound(b+1, b+1+cnt, a[i]) - b;
    67     }
    68 
    69     sort(Q+1, Q+1+M, cmp);              //莫队分区
    70 
    71     solve();
    72 
    73     return 0;
    74 }
  • 相关阅读:
    SQLServer之创建AFETER DELETE触发器
    SQLServer之创建DML AFTER UPDATE触发器
    SQLServer之创建DML AFTER INSERT触发器
    css制作环形进度条
    curl教程2
    windows下更改鼠标滚轮方向
    curl tutorial with examples of usage
    为npm设置代理
    日期类型的input元素设置默认值为当天
    加盐密码哈希:如何正确使用
  • 原文地址:https://www.cnblogs.com/ymzjj/p/10397912.html
Copyright © 2011-2022 走看看