您的位置:首页 > 产品设计 > UI/UE

hdu 5286 wyh2000 and sequence 分块

2016-07-05 23:07 393 查看
学别人的。。。。


对于答案我们不好用线段树维护,但是n只有50000,所以我们可以用分块的方法,来处理

令f(l,r)表示[l,r]的答案。
我们对于序列分块,对于第i块,令Si为第i块的左端点。
令g(a,b)表示第a块开头到第b块末尾这一段序列的答案。下面我们讨论如何求g(a,b)。
我们枚举a,再枚举j(Sa≤j≤n),考虑j 转移到j+1,f(Sa,j)和f(Sa,j+1)的关系。
f(Sa,j+1)=f(Sa,j)−Asum(Aj+1)j+1+Asum(Aj+1)+1j+1
其中sum(x)表示x在区间[Sa,j]中出现的次数,这样我们就能用nn‾‾√logn的时间求出g(a,b)。
令h(i,j)表示i在前j个块中出现的次数,这个也很容易用n‾‾√的时间求出。
考虑询问[l,r],两端的我们可以暴力求出来,中间的块内答案可以直接用g数组求出。然后我们可以用类似求g数组的方法将两端的数加入中间的块内。复杂度O(Qn‾‾√logn)。
/*************************************************************************
> File Name: hdu5286.cpp
> Author: TechMonster
> Mail: 928221136@qq.com
> Created Time: 二  7/ 5 20:51:25 2016
************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
#define ls (o<<1)
#define rs (o<<1|1)
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x, y) memcpy(x, y, sizeof(x))
#define PB(x) push_back(x);
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 50010;
const LL M = 1000000007;

int n,m,a
,b
,color,vis
,lim;
vector<LL>Pow
;
int prefix[250][50010],belong
;
LL sum[250][250];
void solve()
{
scanf("%d%d",&n,&m);
lim = sqrt(n);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
b[i] = a[i];
belong[i] = i/lim + 1;
}
sort(b+1,b+1+n);
color = unique(b+1,b+1+n) - b - 1;
MS(vis,0);
for(int i = 1; i <= n; ++i)
a[i] = lower_bound(b+1,b+1+color,a[i]) - b,vis[a[i]]++;

for(int i = 1; i <= color; ++i)
{
Pow[i].clear();
Pow[i].PB(0);
LL ret = 1,p = b[i];
for(int j = 1; j <= vis[i]; ++j) ret = (ret*p)%M,Pow[i].PB(ret);
}

int top = n/lim+1,L,R;
for(int i = 1; i <= top; ++i)
{
memset(vis,0,sizeof(int)*(color+3));
L = max(1,(i-1)*lim);
R = min(n,i*lim-1);
for(int j = 1; j <= color; ++j)
prefix[i][j] = prefix[i-1][j];
for(int j = L; j <= R; ++j)
prefix[i][a[j]]++;

sum[i][belong[L]] = Pow[a[L]][1]; vis[a[L]]++;
for(int j = L+1; j <= n; ++j)
{
sum[i][belong[j]] = (sum[i][belong[j-1]] - Pow[a[j]][vis[a[j]]] + Pow[a[j]][vis[a[j]]+1])%M;
vis[a[j]]++;
}
}
int la = 0,A,B,c;
LL ret;
for(int i = 1; i <= m; ++i)
{
scanf("%d%d",&A,&B);
L = min((A^la)%n,(B^la)%n)+1;
R = max((A^la)%n,(B^la)%n)+1;
if(belong[R]-belong[L] <= 1)
{
ret = 0;
memset(vis,0,sizeof(int)*(color+3));
for(int i = L; i <= R; ++i)
{
c = a[i];
ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
vis[c]++;
}
}
else
{
int l = (belong[L])*lim-1, r = belong[R]*lim - lim;
memset(vis,-1,sizeof(int)*(color+3));
ret = sum[belong[L]+1][belong[R]-1];
for(int i = L; i <= l; ++i)
{
c = a[i];
if(vis[c] == -1) vis[c] = prefix[belong[R]-1][c] - prefix[belong[L]][c];
ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
vis[c]++;
}
for(int i = r; i <= R; ++i)
{
c = a[i];
if(vis[c] == -1) vis[c] = prefix[belong[R]-1][c] - prefix[belong[L]][c];
ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
vis[c]++;
}
}
ret = (ret%M+M)%M;
la = ret;
printf("%d\n",la);
}

}
int main()
{
int T;
scanf("%d",&T);
while(T--)
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: