树状数组+欧拉降幂

◇◆丶佛笑我妖孽 提交于 2019-12-03 07:17:58

链接:https://ac.nowcoder.com/acm/problem/17190
来源:牛客网

题目描述

给一个长为n的序列,m次操作,每次操作:
1.区间[l,r][l,r][l,r]加xxx
2.对于区间[l,r][l,r][l,r],查询a[l]a[l+1]a[l+2]......a[l]^{a[l+1]^{a[l+2]......}}a[l]a[l+1]a[l+2]......modmodmoppp,一直到aaa-rrr
请注意每次的模数不同。

输入描述:

第一行两个整数 n,m 表示序列长度和操作数接下来一行,n个整数,表示这个序列接下来m行,可能是以下两种操作之一:操作1:区间[l,r]加上 x操作2:查询区间[l,r]的那个式子mod p的值

输出描述:

对于每个询问,输出一个数表示答案
示例1

输入

复制
6 4
1 2 3 4 5 6
2 1 2 10000007
2 2 3 5
1 1 4 1
2 2 4 10

输出

复制
1
3
1

备注:

n , m <= 500000序列中每个数在 [1,2e9] 内,x <= 2e9 , p <= 2e7
#include<bits/stdc++.h>
#include<tr1/unordered_map>
typedef long long ll;
using namespace std;
const int maxn=2e7+9;
const int MAX=1e5+9; 
bool vis[maxn];
int cnt,prim[maxn],phi[maxn],n;
ll a[maxn];
typedef pair<ll,int>P;

inline int lowbit(int x)
{
	return x&(-x);
}

inline void update(int l,int k)
{
	while(l<=n)
	{
		a[l]+=k;
		l+=lowbit(l);
	}
}

inline ll query(int l)
{
	ll ans=0;
	while(l)
	{
		ans+=a[l];
		l-=lowbit(l);
	}
	return ans;
}

inline ll read()
{
	ll res=0;
	char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))res=(res<<1)+(res<<3)+c-48,c=getchar();
	return res;
}

inline void init()
{
	ll i,j;
	vis[1]=phi[1]=1;
	for(i=2;i<=maxn-9;i++)
	{
		if(!vis[i])
		{
			prim[++cnt]=i;
			phi[i]=i-1;
		}
		for(j=1;j<=cnt&&i*prim[j]<=maxn-9;++j)
		{
			vis[i*prim[j]]=1;
			if(i%prim[j]==0)
			{
				phi[i*prim[j]]=phi[i]*prim[j];break;
			}
			phi[i*prim[j]]=phi[i]*(prim[j]-1);
		}
	}
}

P Pow(ll a,ll b,ll p)
{
	ll ans=1,temp=1,i;
	int flag=0;
	for(i=1;i<=b;i++)
	{
		temp=temp*a;
		if(temp>=p)
		{
			flag=1;break;
		}
	}
	a%=p;
	while(b)
	{
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return P(ans,flag);
}

inline P getans(ll l,ll r,ll p)
{
	ll a=query(l);
	if(a==1||l==r||p==1)return P(a%p,a>=p?1:0);
	P b=getans(l+1,r,phi[p]);
	if(b.second)b.first+=phi[p];
	return Pow(a,b.first,p);
}

int main()
{
	int m,i;
	scanf("%d%d",&n,&m);
	init();
	for(i=1;i<=n;i++)
	{
		ll a;
		scanf("%lld",&a);
		update(i,a);
		update(i+1,-a);
	}
	while(m--)
	{
		int opt;
		ll l,r,x;
		scanf("%d%lld%lld%lld",&opt,&l,&r,&x);
		if(opt==1)
		{
			update(l,x);
			update(r+1,-x);
		}
		else
		{
			printf("%lld\n",getans(l,r,x).first);
		}
	}
}

  

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!