标签:数据结构 解题报告
处理范围
处理一类无修改的离线区间询问问题
流程
- 已知[L, R]区间内的答案;
- O(1)内可以得到[L-1, R], [L+1, R], [L, R-1], [L, R+1]区间内的答案;
- 通过从[L, R]到[L’, R’]的曼哈顿路径得到区间[L’, R’]内的答案,复杂度O(|L-L’|+|R-R’|)。
- 对询问区间分块排序后再询问,复杂度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.com
* 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;
}