1. 程式人生 > >【BZOJ4869】相逢是問候(線段樹,歐拉定理)

【BZOJ4869】相逢是問候(線段樹,歐拉定理)

post class problem spa bzoj struct printf 計算 oid

【BZOJ4869】相逢是問候(線段樹,歐拉定理)

題面

BZOJ

題解

根據歐拉定理遞歸計算(類似上帝與集合的正確用法)
所以我們可以用線段樹維護區間最少的被更新的多少次
如果超過了\(\varphi\)的限制
就不用再計算了
如果需要計算就每次暴力算
這樣的復雜度\(O(nlog^2)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map> #include<vector> #include<queue> using namespace std; #define lson (now<<1) #define rson (now<<1|1) #define MAX 80000 #define ll long long inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-'
)ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int a[MAX],C,P,n,m; ll phi[MAX],tot; ll Phi(ll x) { ll ret=x; for(ll i=2;i*i<=x;++i) if(x%i==0) { ret=ret/i*(i-1
); while(x%i==0)x/=i; } if(x>1)ret=ret/x*(x-1); return ret; } ll fpow(ll a,ll b,ll P) { long long s=1; bool fl=false,f2=false; while(b) { if(b&1)s=1ll*s*a,fl|=f2; if(s>=P)fl=true,s%=P; a=a*a; if(a>=P)f2=true,a%=P; b>>=1; } if(fl)s+=P; return s; } struct Node{long long sum;int tt;}t[MAX<<2]; inline void Build(int now,int l,int r) { if(l==r){t[now].sum=a[l]=read();return;} int mid=(l+r)>>1; Build(lson,l,mid);Build(rson,mid+1,r); t[now].sum=(t[lson].sum+t[rson].sum)%P; } ll Calc(int l,int r,ll x,ll P) { if(l==r)return fpow(x,1,P); return fpow(C,Calc(l+1,r,x,phi[l+1]),P); } void Modify(int now,int l,int r,int L,int R) { if(t[now].tt>=tot)return; if(l==r) { t[now].sum=Calc(0,++t[now].tt,a[l],P)%P; //t[now].sum=fpow(C,a[l],P)%P; //a[l]=fpow(C,a[l],phi[1]); return; } int mid=(l+r)>>1; if(L<=mid)Modify(lson,l,mid,L,R); if(R>mid)Modify(rson,mid+1,r,L,R); t[now].tt=min(t[lson].tt,t[rson].tt); t[now].sum=(t[lson].sum+t[rson].sum)%P; } int Query(int now,int l,int r,int L,int R) { if(L<=l&&r<=R)return t[now].sum; int mid=(l+r)>>1;ll ret=0; if(L<=mid)ret=(ret+Query(lson,l,mid,L,R))%P; if(R>mid)ret=(ret+Query(rson,mid+1,r,L,R))%P; return ret; } int main() { n=read();m=read();P=read();C=read(); Build(1,1,n); phi[0]=P; for(tot=1;;++tot) { phi[tot]=Phi(phi[tot-1]); if(phi[tot]==1)break; } phi[++tot]=1; while(m--) { int opt=read(),l=read(),r=read(); if(opt)printf("%d\n",Query(1,1,n,l,r)); else Modify(1,1,n,l,r); } return 0; }

【BZOJ4869】相逢是問候(線段樹,歐拉定理)