admin管理员组

文章数量:1612097

标签:数据结构 解题报告


处理范围

处理一类无修改的离线区间询问问题

流程

  1. 已知[L, R]区间内的答案;
  2. O(1)内可以得到[L-1, R], [L+1, R], [L, R-1], [L, R+1]区间内的答案;
  3. 通过从[L, R]到[L’, R’]的曼哈顿路径得到区间[L’, R’]内的答案,复杂度O(|L-L’|+|R-R’|)。
  4. 对询问区间分块排序后再询问,复杂度O( nn )(amazing!)

为什么要分块?个人理解,总体上它减少了排序后相邻两个询问区间的跨度。


Problem D Curious Cupid

Source: 2016 Asia Hong Kong Online Preliminary

题意

有N男N女排成两列,每人会讲一种语言。语言数为K,M个询问,[L,R]区间内可配对(讲相同语言)的最多是几对。
(1≤N≤50000,1≤M≤50000,1≤K≤1000000)

分析

基于莫队算法的思路,每次update的时候更新某种语言人数,取男女中的较小值更新到答案中。

代码

/*--------------------------------------------
 * File Name: Mo's Algorithm
 * Author: Danliwoo
 * Mail: Danliwoo@outlook
 * Created Time: 2016-10-03 17:10:42
--------------------------------------------*/

#include <bits/stdc++.h>
using namespace std;
#define N 51000
#define K 1000100
int n, m, k;
int a[N], b[N], pos[N], c[2][K], ans[N], cnt;
struct node {
    int l, r, id;
    void sc(int i){
        scanf("%d%d", &l, &r);
        id = i;
    }
}p[N];
bool cmp(node a, node b) {
    if(pos[a.l] == pos[b.l]) return a.r < b.r;
    return pos[a.l] < pos[b.l];
}
void update(int x, int y) {
    if(a[x] != b[x]) cnt -= min(c[0][a[x]], c[1][a[x]]) + min(c[0][b[x]], c[1][b[x]]);
    else cnt -= min(c[0][a[x]], c[1][a[x]]);
    c[0][a[x]] += y;
    c[1][b[x]] += y;
    if(a[x] != b[x]) cnt += min(c[0][a[x]], c[1][a[x]]) + min(c[0][b[x]], c[1][b[x]]);
    else cnt += min(c[0][a[x]], c[1][a[x]]);
}
void pri() {
    for(int j = 0;j < 2;j++)
        for(int i = 0;i < n;i++)
            printf("%d%c", c[j][i], " \n"[i==n-1]);
}
void solve() {
    memset(c, 0, sizeof(c));
    int pl = 0, pr = 0;
    cnt = a[0] == b[0] ? 1 : 0;
    c[0][a[0]]++; c[1][b[0]]++;
    for(int i = 0;i < m;i++) {
        int id = p[i].id, l = p[i].l, r = p[i].r;
        for(int j = pr + 1;j <= r;j++)
            update(j, 1);
        for(int j = pr;j > r;j--)
            update(j, -1);
        for(int j = pl;j < l;j++)
            update(j, -1);
        for(int j = pl-1; j >= l;j--)
            update(j, 1);
        pr = r; pl = l;
        ans[id] = cnt;
    }
    for(int i = 0;i < m;i++)
        printf("%d\n", ans[i]);
}
int main() {
    while(~scanf("%d%d%d", &n, &m, &k)) {
        for(int i = 0;i < n;i++)
            scanf("%d", &a[i]);
        for(int i = 0;i < n;i++)
            scanf("%d", &b[i]);
        int bk = sqrt(n + 1.0);
        for(int i = 0;i < n;i++)
            pos[i] = i / bk;
        for(int i = 0;i < m;i++)
            p[i].sc(i);
        sort(p, p+m, cmp);
        solve();
    }
    return 0;
}

本文标签: AsiaCupidProblemcuriousPreliminary