Yandex.Algorithm 2011 Round 2-D - Powerful array-莫队算法(分块算法)
2016-05-13 17:31
555 查看
http://codeforces.com/contest/86/problem/D
莫队算法就是处理这类能O1从区间【l,r】得到 【l-1,r】【l,r+1】,不带修改的区间查询的一类问题。
题目要求任意 subarray 的 cnt[a[i]]*cnt[a[i]]*a[i]
按照套路,把所有区间按 左端点 所在块作第一关键字,右端点第二关键字 排序
遍历,预处理第一次询问后,每次询问暴力求解,转移如下:
res -= cnt[a[i]]*cnt[a[i]]*a[i];
cnt[a[i]]++;
res += cnt[a[i]]*cnt[a[i]]*a[i];
算法复杂度为q*sqrt n
考虑右指针,先是按照递增顺序移动,假设当前块右指针在最右端,当下一块时,需移动到最左端,那么也就是每跨越一个块,最多移动O(N),总共sqrtn个块,复杂度n*sqrtn
考虑左指针如果在同一块,移动量不超过sqrtn【在一块内嘛】
如果是跨越一块,移动量最多不超过2*sqrtn【块长只有sqrtn】
复杂度(q*sqrtn)
总复杂度(q+n)*sqrtn
----------------------------------------------------------
有一点 add move 的时候直接那刚才的暴力转移会超时,
因为每次变化只有1, 也就是 x*x*a 变成 (x+1)*(x+1)*a,显然我们直接加上 a*(2*x+1)就好了。。。最后跑了 1.9S
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define N 200100
typedef long long ll;
int a
, cnt[N*5];
ll ans
, res;
int L, R;
struct node
{
int x, y, l, p;
} q
;
bool cmp(const node &x, const node &y)
{
if (x.l == y.l) return x.y < y.y;
return x.l < y.l;
}
void query(int x, int y, int flag)
{
if (flag)
{
for (int i=x; i<L; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
for (int i=L; i<x; i++)
{
res += (-cnt[a[i]]*2+1)*a[i];
cnt[a[i]]--;
}
for (int i=y+1; i<=R; i++)
{
res += (-cnt[a[i]]*2+1)*a[i];
cnt[a[i]]--;
}
for (int i=R+1; i<=y; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
}
else
{
for (int i=x; i<=y; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
}
L = x, R = y;
}
int main()
{
int n, t;
scanf("%d%d", &n, &t);
for (int i=1; i<=n; i++) scanf("%d", &a[i]);
int block_size = sqrt(1.0*n);
for (int i=0; i<t; i++)
{
scanf("%d%d", &q[i].x, &q[i].y);
q[i].l = q[i].x / block_size;
q[i].p = i;
}
sort(q, q+t, cmp);
res = 0;
for (int i=0; i<t; i++)
{
query(q[i].x, q[i].y, i);
ans[q[i].p] = res;
}
for (int i=0; i<t; i++) printf("%I64d\n", ans[i]);
return 0;
}
莫队算法就是处理这类能O1从区间【l,r】得到 【l-1,r】【l,r+1】,不带修改的区间查询的一类问题。
题目要求任意 subarray 的 cnt[a[i]]*cnt[a[i]]*a[i]
按照套路,把所有区间按 左端点 所在块作第一关键字,右端点第二关键字 排序
遍历,预处理第一次询问后,每次询问暴力求解,转移如下:
res -= cnt[a[i]]*cnt[a[i]]*a[i];
cnt[a[i]]++;
res += cnt[a[i]]*cnt[a[i]]*a[i];
算法复杂度为q*sqrt n
考虑右指针,先是按照递增顺序移动,假设当前块右指针在最右端,当下一块时,需移动到最左端,那么也就是每跨越一个块,最多移动O(N),总共sqrtn个块,复杂度n*sqrtn
考虑左指针如果在同一块,移动量不超过sqrtn【在一块内嘛】
如果是跨越一块,移动量最多不超过2*sqrtn【块长只有sqrtn】
复杂度(q*sqrtn)
总复杂度(q+n)*sqrtn
----------------------------------------------------------
有一点 add move 的时候直接那刚才的暴力转移会超时,
因为每次变化只有1, 也就是 x*x*a 变成 (x+1)*(x+1)*a,显然我们直接加上 a*(2*x+1)就好了。。。最后跑了 1.9S
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define N 200100
typedef long long ll;
int a
, cnt[N*5];
ll ans
, res;
int L, R;
struct node
{
int x, y, l, p;
} q
;
bool cmp(const node &x, const node &y)
{
if (x.l == y.l) return x.y < y.y;
return x.l < y.l;
}
void query(int x, int y, int flag)
{
if (flag)
{
for (int i=x; i<L; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
for (int i=L; i<x; i++)
{
res += (-cnt[a[i]]*2+1)*a[i];
cnt[a[i]]--;
}
for (int i=y+1; i<=R; i++)
{
res += (-cnt[a[i]]*2+1)*a[i];
cnt[a[i]]--;
}
for (int i=R+1; i<=y; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
}
else
{
for (int i=x; i<=y; i++)
{
res += (cnt[a[i]]*2+1)*a[i];
cnt[a[i]]++;
}
}
L = x, R = y;
}
int main()
{
int n, t;
scanf("%d%d", &n, &t);
for (int i=1; i<=n; i++) scanf("%d", &a[i]);
int block_size = sqrt(1.0*n);
for (int i=0; i<t; i++)
{
scanf("%d%d", &q[i].x, &q[i].y);
q[i].l = q[i].x / block_size;
q[i].p = i;
}
sort(q, q+t, cmp);
res = 0;
for (int i=0; i<t; i++)
{
query(q[i].x, q[i].y, i);
ans[q[i].p] = res;
}
for (int i=0; i<t; i++) printf("%I64d\n", ans[i]);
return 0;
}
相关文章推荐
- CodeForces 451D Count Good Substrings
- go 的 protoc 插件调用逻辑
- Category在开发中使用的淫技之——改变系统方法
- 最优Django环境配置
- golang中的类型和接口
- E - Gerald's Hexagon
- Mongo命令批量更新某一数组字段的顺序
- download and install Mongo db
- Google 开源了世界上最准确的语言解析器 Parsey McParseface
- 个人godaddy域名备案解决方案
- Going deeper with convolutions:卷积的更深一些
- 思源黑体下载 - Google 联合 Adobe 发布免费开源优雅的设计字体 (简繁中文/日韩文)
- wordpress 访问 gravatar 以及 google map api 慢的解决办法
- django 消息模块 (messages ) 的使用
- go 方法
- mac修改host文件,让你的mac轻松上google
- django 基础入门(二)
- Fusion Tables 图层用于呈现 Google Fusion Tables 中包含的数据
- Django基础(二)—— models
- 多边形glPolygonMode glFrontFace glCullFace glPolygonStipple