【BZOJ4869】相逢是问候(线段树,欧拉定理)

【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;
}

posted @ 2018-01-22 17:28  小蒟蒻yyb  阅读(367)  评论(2编辑  收藏  举报