毒瘤数据结构之奈芙莲树
Posted yzhang-rp-inf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了毒瘤数据结构之奈芙莲树相关的知识,希望对你有一定的参考价值。
〇、奈芙莲美图欣赏
奈芙莲也是很可爱呢
~~一、什么是奈芙莲树
是不是大佬蒟蒻yzhang又发明了珂学算法(逃~)
奈芙莲树,听起来好dl
实际呢只是题目和奈芙莲有关系,所以起了这个珂学的名字(逃~
是一种奇怪的数据结构瞎搞
是由线段树改造而成(平易近人)
二、奈芙莲树资瓷什么操作
资瓷一些奇怪的操作(大雾)
1.维护:区间加减(奈芙莲树好型很简单)
(实际很简单)
2.查询:有区间【l,r】,求(a[l]^a[l+1]^a[l+2]^...^a[r-1]^a[r])%p
a^b表示a的b次方
(好毒瘤啊)
三、拓展欧拉定理
什么??!我们不是要学奈芙莲树吗?拓展欧拉是什么鬼,我数论很差啊!!!
题目让你求a[l]^a[l+1]^a[l+2]^...^a[r-1]^a[r]
怎么求??!
暴力? 快速幂? 高精? Python?
要用拓展欧拉定理(毒瘤)
什么是拓展欧拉定理(逃~?
我们先说欧拉定理
以下所有“==”表示同余
a^phi[p]==1(mod p) gcd(a,p)=1
phi是什么?
表示小于p的正整数中与p互质的数的个数 gcd不用说 (证明略)
我们再说拓展欧拉定理
这是核心
gcd(a,b)=1 a^b==a^(b%phi[p]) (mod p)
gcd(a,b)!=1&&b<phi[p] 直接快速幂
gcd(a,b)!=1&&b>=phi[p] a^b==a^(b%phi[p]+phi[p]) (mod p)
(证明略,不懂得赶紧问度娘)
关于扩展欧拉定理的题
No1. Luogu P4139 上帝与集合的正确用法
链接:https://www.luogu.org/problemnew/show/P4139
No2. Luogu P3747 [六省联考2017]相逢是问候
链接:https://www.luogu.org/problemnew/show/P3747
四、奈芙莲树有哪些题
No1. Luogu P3934 Nephren Ruq Insania
简介:板子题,名称的来源
链接:https://www.luogu.org/problemnew/show/P3934
No.2 Luogu P4118 [Ynoi2016]炸脖龙I
简介:板子题,Luogu不能交,也许bzoj有
题面链接:https://www.luogu.org/problemnew/show/P4118
五、奈芙莲树的初始化
没什么,预处理质数和欧拉函数。
inline void calcprime()
{
phi[1]=1; //边界条件
for(register int i=2;i<=lim;++i) //日常卡常
{
if(!vis[i])
{
prime[++cnt]=i; //筛法
phi[i]=i-1; //质数只有自己不与它互质
}
for(register int j=1;j<=cnt;++j)
{
int t=i*prime[j]; //筛法
if(t>lim) //超过最大(题目数据范围)
break;
vis[t]=true; //表明不是质数
if(i%prime[j]==0) //特判欧拉函数
{
phi[t]=phi[i]*prime[j];
break;
}
phi[t]=phi[i]*(prime[j]-1);
}
}
}
预处理就这样简单(逃~
五、奈芙莲树的查询操作
基于普通的线段树
再用拓展欧拉公式一求就行
inline ll querysum(int x,int l,int r,int q) //真正的查询
{
if(l==r) //特判
return sum[x];
int mid=(l+r)>>1;
pushdown(x,l,r); //把lazy_tag下放
if(q<=mid)
return querysum(x<<1,l,mid,q);
else
return querysum(x<<1|1,mid+1,r,q);
}
inline ll query(int q) //查询
{
if(las[q]==m) //是否有记录
return a[q];
las[q]=m; //计入记录
return a[q]=querysum(1,1,n,q); //计入记录+返回
}
inline ll fpow(int x,ll p,int q) //快速幂
{
int ans=1;
for(;p;p>>=1,x=1LL*x*x%q)
if(p&1)
ans=1LL*ans*x%q;
return ans;
}
inline ll calc(int l,int r,int p)
{
if(query(l)%p==0) //一堆特判
return 0;
if(p==1)
return 1;
if(l==r)
{
ll curt=query(l);
return curt%p+(curt>=p)*p; //公式
}
//一堆瞎搞
int f=min(r,l+5);
for(register int i=l+1;i<=f;++i)
if(query(i)==1)
{
f=i;
break;
}
ll last=query(f),q=0;
for(register int i=f-1;i>=l+1;--i)
{
q=last,last=1;
while(q--)
{
last*=query(i);
if(last>=phi[p])
return fpow(query(l)%p,calc(l+1,r,phi[p])+phi[p],p);
}
}
return fpow(query(l)%p,last,p);
}
实际很简单(大雾)
六、奈芙莲树的完整程序
#pragma GCC optimize("-O3")
#include <bits/stdc++.h>
#define Chtholly_is_so_cute ios::sync_with_stdio(0);
#define ll long long
using namespace std;
const int N=500005;
const int M=20000005;
const int inf=N-4;
const int lim=20000000;
int n,m,x,phi[M],prime[M],cnt;
ll c[N],a[N];
bool vis[M];
int las[N];
ll sum[N<<2],tag[N<<2],fone[N<<2];
inline int read()
{
int f=1,x=0;char ch;
do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
return f*x;
}
inline void calcprime()
{
phi[1]=1;
for(register int i=2;i<=lim;++i)
{
if(!vis[i])
{
prime[++cnt]=i;
phi[i]=i-1;
}
for(register int j=1;j<=cnt;++j)
{
int t=i*prime[j];
if(t>lim)
break;
vis[t]=true;
if(i%prime[j]==0)
{
phi[t]=phi[i]*prime[j];
break;
}
phi[t]=phi[i]*(prime[j]-1);
}
}
}
inline void pushup(int x)
{
sum[x]=sum[x<<1]+sum[x<<1|1];
fone[x]=min(fone[x<<1],fone[x<<1|1]);
}
inline void build(int x,int l,int r)
{
fone[x]=inf;
if(l==r)
{
sum[x]=a[l];
if(a[l]==1)
fone[x]=l;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
inline void pushdown(int x,int l,int r)
{
if(tag[x])
{
int mid=(l+r)>>1;
int ls=x<<1;
int rs=ls+1;
tag[ls]+=tag[x];
tag[rs]+=tag[x];
sum[ls]+=tag[x]*1LL*(mid-l+1);
sum[rs]+=tag[x]*1LL*(r-mid);
fone[ls]=inf;
fone[rs]=inf;
tag[x]=0;
}
}
inline void update(int x,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
sum[x]+=1LL*(r-l+1)*v;
tag[x]+=v;
fone[x]=inf;
return;
}
pushdown(x,l,r);
int mid=(l+r)>>1;
if(L<=mid)
update(x<<1,l,mid,L,R,v);
if(R>mid)
update(x<<1|1,mid+1,r,L,R,v);
pushup(x);
}
inline ll querysum(int x,int l,int r,int q)
{
if(l==r)
return sum[x];
int mid=(l+r)>>1;
pushdown(x,l,r);
if(q<=mid)
return querysum(x<<1,l,mid,q);
else
return querysum(x<<1|1,mid+1,r,q);
}
inline ll query(int q)
{
if(las[q]==m)
return a[q];
las[q]=m;
return a[q]=querysum(1,1,n,q);
}
inline ll fpow(int x,ll p,int q)
{
int ans=1;
for(;p;p>>=1,x=1LL*x*x%q)
if(p&1)
ans=1LL*ans*x%q;
return ans;
}
inline ll calc(int l,int r,int p)
{
if(query(l)%p==0)
return 0;
if(p==1)
return 1;
if(l==r)
{
ll curt=query(l);
return curt%p+(curt>=p)*p;
}
int f=min(r,l+5);
for(register int i=l+1;i<=f;++i)
if(query(i)==1)
{
f=i;
break;
}
ll last=query(f),q=0;
for(register int i=f-1;i>=l+1;--i)
{
q=last,last=1;
while(q--)
{
last*=query(i);
if(last>=phi[p])
return fpow(query(l)%p,calc(l+1,r,phi[p])+phi[p],p);
}
}
return fpow(query(l)%p,last,p);
}
int main()
{
Chtholly_is_so_cute
calcprime();
n=read(),m=read();
for(register int i=1;i<=n;++i)
las[i]=-1;
for(register int i=1;i<=n;++i)
a[i]=read();
build(1,1,n);
while(m--)
{
int opt=read(),l=read(),r=read(),v=read();
if(opt==1)
update(1,1,n,l,r,v);
else
cout<<(calc(l,r,v)%v)<<endl;
}
return 0;
}
以上是关于毒瘤数据结构之奈芙莲树的主要内容,如果未能解决你的问题,请参考以下文章