清橙A1206
题目链接:
http://www.tsinsen.com/A1206
题意:
中文题
思路:
莫队算法入门题。
从昨晚上看到现在也是有够笨的……
莫队算法有一个引入的知识是曼哈顿最小生成树,不过这个好像比较难的样子,因为可能会用到平衡树或者线段树。只需要知道一个结论就可以,那就是对于一个二维平面图中一些点,如果要构造一个曼哈顿距离的最小生成树,那么选取边的时候对于一个点只需要最多选取8条边(O(8*n)),而不是和所有的点建立边然后求最小生成树O(n*n)
详见http://blog.csdn.net/huzecong/article/details/8576908
莫队算法借用了曼哈顿最小生成树的思想。
莫队算法用于求对一些区间的询问,那么把一个个询问看成二维平面图上的点[l,r],然后就可以用类似曼哈顿最小生成树的知识来解了。也就是说,如果要求的某个点的值,找一个最近的点去求,消耗最小。整体更新的消耗,就是曼哈顿最小生成树的边的大小。
当然上面不知道也可以,因为具体实现的时候并没有用平衡树或者线段树这么高端的算法维护。采用一种分块处理的办法,即把所有点分成sqrt(n)块,按照块排序后在再按照右端点排序,然后暴力求解。可以证明这样暴力复杂度比较小。
详见http://blog.csdn.net/bossup/article/details/39236275
枉我看这么久,说白了就是暴力啊……
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
const int MAXN = 50000 + 5;
int pos[MAXN];
struct Q
{
int l, r;
int id;
}q[MAXN];
bool cmp1(Q a, Q b)
{
if(pos[a.l] == pos[b.l]) return a.r < b.r;
else return a.l < b.l;
}
bool cmp2(Q a, Q b){return a.id < b.id;}
int data[MAXN];
LL num[MAXN];
int blocksize;
LL cnt;
LL up[MAXN], dw[MAXN];
void update(int u, int v)
{
cnt -= num[u] * num[u];
num[u] += v;
cnt += num[u] * num[u];
}
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF){
memset(num, 0, sizeof(num));
blocksize = sqrt(1.0 * n);
for(int i = 1 ; i <= n ; i++){
scanf("%d", &data[i]);
pos[i] = (i - 1) / blocksize;
}
for(int i = 0 ; i < m ; i++){
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort(q, q + m, cmp1);
int curr = 0, curl = 1;
cnt = 0;
for(int i = 0 ; i < m ; i++){
if(q[i].l == q[i].r){
up[q[i].id] = 0;
dw[q[i].id] = 1;
continue;
}
if(curr != q[i].r){
for(int j = curr + 1; j <= q[i].r ; j++) update(data[j], 1);
for(int j = curr ; j > q[i].r ; j--) update(data[j], -1);
}
if(curl != q[i].l){
for(int j = curl ; j < q[i].l ; j++) update(data[j], -1);
for(int j = curl - 1 ; j >= q[i].l ; j--) update(data[j], 1);
}
curr = q[i].r, curl = q[i].l;
up[q[i].id] = cnt - (q[i].r - q[i].l + 1);
dw[q[i].id] = (LL)(q[i].r - q[i].l + 1) * (q[i].r - q[i].l);
LL temp = __gcd(up[q[i].id], dw[q[i].id]);
up[q[i].id] /= temp;
dw[q[i].id] /= temp;
// printf("i = %d, ans = %I64d, q[i].id = %d, l = %d, r = %d\n", i, cnt, q[i].id, q[i].l, q[i].r);
}
for(int i = 0 ; i < m ; i++)
printf("%I64d/%I64d\n", up[i], dw[i]);
}
return 0;
}