hdu 5286 wyh2000 and sequence 分块

学别人的。。。。微笑

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


  
  
   
   f(l,r)
   
   
  
  表示
  
  
   
   [l,r]
   
   
  
  的答案。
我们对于序列分块,对于第
  
  
   
   i
   
   
  
  块,令
  
  
   
   Si
   
   
  
  为第
  
  
   
   i
   
   
  
  块的左端点。
令
  
  
   
   g(a,b)
   
   
  
  表示第
  
  
   
   a
   
   
  
  块开头到第
  
  
   
   b
   
   
  
  块末尾这一段序列的答案。下面我们讨论如何求
  
  
   
   g(a,b)
   
   
  
  。
我们枚举
  
  
   
   a
   
   
  
  ,再枚举
  
  
   
   j(Sajn)
   
   
  
  ,考虑
  
  
   
   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[N],b[N],color,vis[N],lim;
vector<LL>Pow[N];
int prefix[250][50010],belong[N];
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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值