CF633H Fibonacci-ish II 莫队 线段树 矩阵
作者:互联网
题意很简明 同时给人以不可做感。
直接暴力大概是\(n^2log\)的 优化一下提前排好序 从小到大枚举数字再枚举询问可以完成\(n^2\)
经过精细的优化竟然可以过了这个题,可能是出题人没有刻意卡或者根本没想到(赛后hack肯定是有的。
直接得到一个区间谁也做不了,考虑线段树维护区间 发现也不太能做。
容易考虑莫队得到每个区间 在加入一个数字的时候 若这个数字不是第一次加入
带来的影响是比它小的数字不变 后面的统一斐波那契数列向后推一项。
后者这个操作可以使用矩阵来做多乘以一个矩阵就能完成区间修改。
删除类似要乘以一个逆矩阵。注意细节。
关于初始化标记的矩阵最好的初始化为 1001这是单位矩阵,比 0000 的意义更明确。
在单点修改x的时候查找x的排名省掉一个树状数组或者说线段树上的一次查询。
pushdown的时候卡卡常不用改变就不改。
最后一个较为关键的是 莫队的排序 由于莫队指针移动一次的复杂度不是O(1) 所以进行奇偶性优化就很关键,可以省掉一大波常数。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000000ll
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-10
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define max(x,y) ((x)<(y)?y:x)
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;
}
const int MAXN=30010;
int n,m,Q,cnt,S,cc;
int gg[2][2],kk[2][2];
int a[MAXN],B[MAXN],c[MAXN],ans[MAXN],w[MAXN],g[MAXN],f[MAXN],v[MAXN];
inline void
struct wy
{
int a,b,sum;
int c[2][2];
}t[MAXN<<2];
struct jl
{
int l,r;
int id;
}s[MAXN];
inline int cmp(jl a,jl b){return B[a.l]==B[b.l]?((B[a.l]&1)?a.r>b.r:a.r<b.r):a.l<b.l;}
inline void discrete()
{
sort(c+1,c+1+n);
rep(1,n,i)if(i==1||c[i]!=c[i-1])c[++cnt]=c[i];
rep(1,n,i)a[i]=lower_bound(c+1,c+1+cnt,a[i])-c;
rep(1,cnt,i)c[i]%=m;
}
inline void build(int p,int l,int r)
{
t[p].c[0][0]=t[p].c[1][1]=1;
if(l==r)return;
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
inline void pushdown(int p)
{
if(t[p].c[0][0]==1&&t[p].c[1][1]==1&&t[p].c[1][0]==0&&t[p].c[0][1]==0)return;
if(sum(p<<1))
{
int ww=(a(p<<1)*t[p].c[0][0]+b(p<<1)*t[p].c[1][0])%m;
b(p<<1)=(a(p<<1)*t[p].c[0][1]+b(p<<1)*t[p].c[1][1])%m;
a(p<<1)=ww;
if(t[p<<1].c[0][0]==1&&t[p<<1].c[1][1]==1&&t[p<<1].c[1][0]==0&&t[p<<1].c[0][1]==0)
rep(0,1,i)rep(0,1,j)t[p<<1].c[i][j]=t[p].c[i][j];
else
{
rep(0,1,i)rep(0,1,j)kk[i][j]=t[p<<1].c[i][j],t[p<<1].c[i][j]=0;
rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p<<1].c[i][j]=(t[p<<1].c[i][j]+kk[i][k]*t[p].c[k][j]);
t[p<<1].c[0][0]%=m;
t[p<<1].c[1][1]%=m;
t[p<<1].c[1][0]%=m;t[p<<1].c[0][1]%=m;
}
}
if(sum(p<<1|1))
{
int ww=(a(p<<1|1)*t[p].c[0][0]+b(p<<1|1)*t[p].c[1][0])%m;
b(p<<1|1)=(a(p<<1|1)*t[p].c[0][1]+b(p<<1|1)*t[p].c[1][1])%m;
a(p<<1|1)=ww;
if(t[p<<1|1].c[0][0]==1&&t[p<<1|1].c[1][1]==1&&t[p<<1|1].c[1][0]==0&&t[p<<1|1].c[0][1]==0)
rep(0,1,i)rep(0,1,j)t[p<<1|1].c[i][j]=t[p].c[i][j];
else
{
rep(0,1,i)rep(0,1,j)kk[i][j]=t[p<<1|1].c[i][j],t[p<<1|1].c[i][j]=0;
rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p<<1|1].c[i][j]=(t[p<<1|1].c[i][j]+kk[i][k]*t[p].c[k][j]);
t[p<<1|1].c[0][0]%=m;t[p<<1|1].c[1][1]%=m;t[p<<1|1].c[1][0]%=m;t[p<<1|1].c[0][1]%=m;
}
}
t[p].c[0][0]=t[p].c[1][1]=1;t[p].c[1][0]=t[p].c[0][1]=0;
}
inline void pushup(int p)
{
a(p)=(a(p<<1)+a(p<<1|1))%m;
b(p)=(b(p<<1)+b(p<<1|1))%m;
sum(p)=sum(p<<1)+sum(p<<1|1);
}
inline void change(int p,int l,int r,int x)
{
if(l==r)
{
++sum(p);
a(p)=c[x]*f[cc]%m;
b(p)=c[x]*f[cc-1]%m;
return;
}
pushdown(p);
int mid=(l+r)>>1;
if(x<=mid)change(p<<1,l,mid,x);
else cc+=sum(p<<1),change(p<<1|1,mid+1,r,x);
pushup(p);
}
inline void change1(int p,int l,int r,int x)
{
if(l==r)
{
a(p)=b(p)=0;
--sum(p);
return;
}
pushdown(p);
int mid=(l+r)>>1;
if(x<=mid)change1(p<<1,l,mid,x);
else change1(p<<1|1,mid+1,r,x);
pushup(p);
}
inline void modify(int p)
{
int ww=(a(p)*gg[0][0]+b(p)*gg[1][0])%m;
b(p)=(a(p)*gg[0][1]+b(p)*gg[1][1])%m;
a(p)=ww;
rep(0,1,i)rep(0,1,j)kk[i][j]=t[p].c[i][j],t[p].c[i][j]=0;
rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p].c[i][j]=(t[p].c[i][j]+kk[i][k]*gg[k][j])%m;
}
inline void modify(int p,int l,int r,int L)
{
if(l>=L)
{
if(sum(p))
{
gg[0][0]=1;gg[0][1]=1;
gg[1][0]=1;gg[1][1]=0;
modify(p);
}
return;
}
pushdown(p);
int mid=(l+r)>>1;
if(L<=mid)modify(p<<1,l,mid,L);
modify(p<<1|1,mid+1,r,L);
pushup(p);
}
inline void modify1(int p,int l,int r,int L)
{
if(l>=L)
{
if(sum(p))
{
gg[0][0]=0;gg[0][1]=1;
gg[1][0]=1;gg[1][1]=m-1;
modify(p);
}
return;
}
pushdown(p);
int mid=(l+r)>>1;
if(L<=mid)modify1(p<<1,l,mid,L);
modify1(p<<1|1,mid+1,r,L);
pushup(p);
}
inline void add(int x)
{
if(v[a[x]]==0)
{
cc=1;change(1,1,cnt,a[x]);
if(a[x]+1<=cnt)modify(1,1,cnt,a[x]+1);
}
++v[a[x]];
}
inline void del(int x)
{
if(v[a[x]]==1)
{
change1(1,1,cnt,a[x]);
if(a[x]+1<=cnt)modify1(1,1,cnt,a[x]+1);
}
--v[a[x]];
}
int main()
{
freopen("1.in","r",stdin);
n=read();m=read();
rep(1,n,i)c[i]=a[i]=read();
Q=read();
rep(1,Q,i)s[i].l=read(),s[i].r=read(),s[i].id=i;
discrete();
f[1]=1;
rep(2,n,i)f[i]=(f[i-1]+f[i-2])%m;
build(1,1,cnt);
S=(int)sqrt(n*1.0)+1;
rep(1,n,i)B[i]=(i-1)/S;
sort(s+1,s+1+Q,cmp);
int L=1,R=0;
rep(1,Q,i)
{
while(R<s[i].r)add(++R);
while(s[i].l<L)add(--L);
while(R>s[i].r)del(R),--R;
while(L<s[i].l)del(L),++L;
ans[s[i].id]=a(1);
}
rep(1,Q,i)printf("%d\n",ans[i]);
return 0;
}
标签:gg,sum,long,II,CF633H,ish,include,莫队,define 来源: https://www.cnblogs.com/chdy/p/16638009.html