我觉得能用线段树就用线段树吧,实在用不了了再来考虑莫队算法,比如下面两道题:
http://codeforces.com/contest/617/problem/E (询问某区间内有多少个子区间的异或值是K)
题解:http://blog.csdn.net/huayunhualuo/article/details/50585720
#include
#define LL long long
using namespace std;
const int Max = 1100000;
const int MAXM = 1<<22;
typedef struct node
{
int L ,R;
int Id;
}Point ;
Point a[Max];
LL sum[Max];
LL ans[Max];
int n,m;
LL k;
int L,R;
LL cnt[MAXM],ant;
bool cmp(Point b,Point c)//将区间分块排序
{
if(b.L/400==c.L/400)
{
return b.Ra[i].R)
{
Dec(sum[R]);
R--;
}
while(La[i].L)
{
--L;
Inc(sum[L]);
}
ans[a[i].Id]=ant;
}
for(int i=1;i<=m;i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}
http://www.lydsy.com/JudgeOnline/problem.php?id=2038 (询问某区间内取到一对值相等的数的概率)
#include
#define LL long long
using namespace std;
const int Max = 50010;
const int MAXM = 50010;
typedef struct node
{
int L ,R;
int Id;
}Point ;
Point a[Max];
LL sum[Max];
pair ans[Max];
int n,m;
int unit;
LL k;
int L,R;
LL cnt[MAXM],ant;
bool cmp(Point b,Point c)//将区间分块排序
{
if(b.L/unit==c.L/unit)
{
return b.Ra[i].R)
{
Dec(sum[R]);
R--;
}
while(La[i].L)
{
--L;
Inc(sum[L]);
}
LL ss=(LL)(a[i].R-a[i].L+1)*(a[i].R-a[i].L)/2; //注意转化LL
LL aa=__gcd(ant,ss);
ans[a[i].Id].first=ant/aa;
ans[a[i].Id].second=(ant==0?1:ss/aa);
}
for(int i=1;i<=m;i++)
{
printf("%lld/%lld\n",ans[i].first,ans[i].second);
}
return 0;
}
http://codeforces.com/problemset/problem/86/D(询问某区间内所有出现过的数字*(它出现过的次数)^2之和)http://www.cnblogs.com/riskyer/archive/2013/07/29/3223621.html
#include
#define LL long long
using namespace std;
const int Max = 2000005;
const int MAXM = 1000005;
typedef struct node
{
int L ,R;
int Id;
}Point ;
Point a[Max];
LL sum[Max];
LL ans[Max];
int n,m;
LL k;
int L,R;
LL cnt[MAXM],ant;
bool cmp(Point b,Point c)//将区间分块排序
{
if(b.L/400==c.L/400)
{
return b.Ra[i].R)
{
Dec(sum[R]);
R--;
}
while(La[i].L)
{
--L;
Inc(sum[L]);
}
ans[a[i].Id]=ant;
}
for(int i=1;i<=m;i++)
{
printf("%I64d\n",ans[i]);
}
return 0;
}
#define LL long long
using namespace std;
const int Max = 2000005;
const int MAXM = 1000005;
typedef struct node
{
int L ,R;
int Id;
}Point ;
Point a[Max];
LL sum[Max];
LL ans[Max];
int n,m;
LL k;
int L,R;
LL cnt[MAXM],ant;
bool cmp(Point b,Point c)//将区间分块排序
{
if(b.L/(int) sqrt(n)!=c.L/(int) sqrt(n))
{
return b.L a[i].R) {
ant -= sum[R] * (2 * cnt[sum[R]]-- - 1);
R--;
}
while(L > a[i].L) {
L--;
ant += sum[L] * (2 * cnt[sum[L]]++ + 1);
}
while(R < a[i].R) {
R++;
ant += sum[R] * (2 * cnt[sum[R]]++ + 1);
}
ans[a[i].Id]=ant;
}
for(int i=1;i<=m;i++)
{
printf("%I64d\n",ans[i]);
}
return 0;
}
这两种情况都不似区间求和,能够通过线段树直接求出来。这时考虑莫队算法http://www.tuicool.com/articles/mYzQZzF
此系列:http://www.2cto.com/kf/201502/376381.html
必须先排序。
【杭电5213】
每组数据给你n(1<=n<=30000)个数字,每个数字都在[1,n]之间。
并且有m(1<=m<=30000)个询问。
还告诉你一个数字K(2<=k<=2n且k为奇数)。
对于第i个询问,给你2个区间,
[l1~r1] [l2~r2],数据保证1<=l1<=r1
a[x]在[l1,r1],a[y]在[l2,r2]且a[x]+a[y]==K.
【分析】
这道题设计到区间询问,而且可以离线处理。于是我们很自然地想到莫队算法。
我们发现数字的范围很小,于是我们可以直接计数1~n的数分别是多少个。
然后因为K为奇数,所以就自然不会需要考虑一个数和自己自成pair。
这道题有一个需要处理的问题,就是一般的莫队是只有一个区间,而这道题却有两个区间,该怎么办?
于是我们还需要——容斥。 (转)
#include
#include
#include
#include