【Codeforces 650D】Zip-line
【Codeforces 633G】Yash And Trees

【Codeforces 633H】Fibonacci-ish II

Zarxdy34 posted @ 2016年3月17日 10:42 in Codeforces with tags 线段树 莫队 , 353 阅读

  首先要知道斐波那契数列一个很有趣的性质:\[F_n = F_{a+1} * F_b + F_a * F_{b-1}\ (a+b=n)\]对所有的整数n,a,b都是满足的,包括负数。式子用矩阵就可以推了。

  首先为将a的值离散化,建棵权值线段树,维护子树中的当前在a的potential序列中的数对答案的贡献。在权值线段树里进行加点删点操作,就可以快速地求出当前的数组a的potential序列。

  用莫队算法处理询问。接下来我们要在\(O(log(n))\)的时间内处理单步操作。

  每次新加入一个点x,那么所有权值大于x的数对应的斐波那契数列中的项都要右移一位。如果每次暴力修改的话复杂度是\(O(n)\)的,所以要用上lazy_tag。

  一眼看过去这个lazy_tag好像不可加的样子。要注意,斐波那契数列在存储时,存相邻的两位往往有奇效。

\[
\ F(k+1)*(a_{1}*F(i)+a_{2}*F(i+1) \cdots) \\
\ +F(k)*(a_{1}*F(i-1)+a_{2}*F(i)+\cdots) \\
\ =(a_{1}*F(i+k)+a_{2}*F(i+k+1))
\]

  (这个排版太差了...宽度太小了QAQ)

  显然,只要维护两个序列就能在\(O(1)\)的时间内打标记和传标记了。

  时间复杂度是\(O(n \sqrt{n} *log(n)\)的,每次在线段树上的操作尽量一次完成,否则可能因为常数太大而T掉。(明明是你自己代码自带大常数

 

 

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=30010;
int p;

int fi[maxn];
inline int f(int x) {if (x>=0) return fi[x];else return ((-x)&1)?fi[-x]:p-fi[-x];}

struct Segment_Tree
{
	int sum1[maxn<<2],sum2[maxn<<2];
	int size[maxn<<2];
	int tag_k[maxn<<2];
	int n;

	#define ls (o<<1)
	#define rs (o<<1|1)
	#define mid ((l+r)>>1)

	void Update(int o) {sum1[o]=(sum1[ls]+sum1[rs])%p;sum2[o]=(sum2[ls]+sum2[rs])%p;size[o]=size[ls]+size[rs];}
	void Mark(int o,int k)
	{
		if (k==1) {int x1=sum1[o];sum1[o]+=sum2[o],sum2[o]=x1;if (sum1[o]>p) sum1[o]-=p;tag_k[o]++;return;}
		int x1=(sum1[o]*f(k+1)+sum2[o]*f(k))%p,x2=(sum1[o]*f(k)+sum2[o]*f(k-1))%p;
		sum1[o]=x1;sum2[o]=x2;tag_k[o]+=k;
	}

	void Push_Down(int o)
	{
		if (tag_k[o])
		{
			Mark(ls,tag_k[o]);
			Mark(rs,tag_k[o]);
			tag_k[o]=0;
		}
	}

	void Change(int o,int l,int r,int x,int v,int w,int c)
	{
		if (l==r)
		{
			if (c==-1) size[o]=sum1[o]=sum2[o]=0;
			else size[o]=1,sum1[o]=v*f(w+1)%p,sum2[o]=v*f(w)%p;
			return;
		}
		Push_Down(o);
		if (x<=mid) Change(ls,l,mid,x,v,w,c),Mark(rs,c);
		else Change(rs,mid+1,r,x,v,w+size[ls],c);
		Update(o);
	}

	void Change(int x,int v,int c) {Change(1,1,n,x,v,0,c);}
	int Result() {return sum1[1];}
}T;

int a[maxn],temp[maxn];
int cnt[maxn];
int ans[maxn];
int n,q,blocksize,ts;

struct Query {int l,r,block,id;bool operator< (const Query &b) const {return block<b.block || block==b.block && r<b.r;}}Q[maxn];

int main()
{
	scanf("%d%d",&n,&p);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	memcpy(temp,a,sizeof(temp));
	sort(temp+1,temp+1+n);
	ts=unique(temp+1,temp+1+n)-(temp+1);
	for (int i=1;i<=n;i++) a[i]=lower_bound(temp+1,temp+1+ts,a[i])-temp;
	for (int i=1;i<=ts;i++) temp[i]%=p;
	T.n=ts;
	fi[1]=1;fi[2]=1;
	for (int i=3;i<=ts+2;i++) fi[i]=(fi[i-1]+fi[i-2])%p;
	blocksize=sqrt(n);
	scanf("%d",&q);
	for (int i=1;i<=q;i++) scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].block=Q[i].l/blocksize,Q[i].id=i;
	sort(Q+1,Q+1+q);
	for (int i=1,l=1,r=0;i<=q;i++)
	{
		while (r<Q[i].r) {r++;cnt[a[r]]++;if (cnt[a[r]]==1) T.Change(a[r],temp[a[r]], 1);}
		while (r>Q[i].r) {cnt[a[r]]--;if (cnt[a[r]]==0) T.Change(a[r],temp[a[r]],-1);r--;}
		while (l>Q[i].l) {l--;cnt[a[l]]++;if (cnt[a[l]]==1) T.Change(a[l],temp[a[l]], 1);}
		while (l<Q[i].l) {cnt[a[l]]--;if (cnt[a[l]]==0) T.Change(a[l],temp[a[l]],-1);l++;}
		ans[Q[i].id]=T.Result();
	}
	for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Back to Top