【BZOJ2038】小Z的袜子(2009国家集训队)-莫队算法

测试地址:小Z的袜子

做法:设f(i)为颜色i在区间[l,r]内出现的次数,则区间[l,r]的答案为:ΣC(2,f(i))/C(2,r-l+1),面对这种东西线段树就无能为力了......怎么办呢?

于是本人今天学习了传说中离线处理区间询问的无敌算法——莫队算法,感觉妙极!莫队算法的讲解见这里。这篇博客中也以这一题作为例题,讲得比较详细了,那我就来讲讲具体实现吧:因为答案的式子中大部分都可以直接通过l和r求出,所以我们只用维护一个ans=Σ(f(i))^2,在从(l,r)转移到(l,r+1)时,假设点r+1的颜色是c,那么ans就比原来多:(f(c)+1)^2-f(c)^2=2*f(c)+1。而从(l,r)转移到(l,r-1)时就略微不同,ans比原来多:(f(c)-1)^2-f(c)^2=-2*f(c)+1。于是可以发现,当我们转移的区间是扩大的时候,ans增加的就是2*f(c)+1,反之就是-2*f(c)+1,然后答案就按照上面那篇博客说的一样计算即可。化成最简分数其实就是分子和分母同除它们的gcd(这个还不懂的话......听天由命吧)。

以下是本人代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m,c[50010],pos[50010],f[50010]={0};
struct query
{
  long long a,b;
  int l,r,id;
}q[50010];

bool cmp1(query a,query b)
{
  return pos[a.l]q[i].l) l--,transfer(l,ans,1);
	if (r>q[i].r) while(r>q[i].r) transfer(r,ans,-1),r--;
	if (q[i].l>l) while(l


你可能感兴趣的:(算法-莫队算法)