BZOJ 5394 [Ynoi2016]炸脖龙 (线段树+拓展欧拉定理)
题目大意:给你一个序列,需要支持区间修改,以及查询一段区间$a_{i}^{a_{i+1}^{a_{i+2}...}}mod\;p$的值,每次询问的$p$的值不同
对于区间修改,由线段树完成,没什么好说的
对于查询,利用"上帝与集合的正确用法"那道题的方法,不断取$\phi(p)$降幂,那么最多迭代$log$层
由于$ai$不一定和$p$互质,需要使用拓展欧拉定理
$ans=ai^{Ans_{i+1}\;mod\;\phi(p)+Ans_{i+1}>=\phi(p)?\phi(p):0}$
每层都记录$Ans_{i}$是否对这一层的$p$取过模,用于判断Ans_{i+1}>=\phi(p)
特判比较多,注意特判的优先级
1.如果$ai mod p==0$,那么不论接下来是几次幂都返回0
2.如果$ai==1$,那么不论$ai$的多少次幂都是1,同时清空已经取过模的标记
3.如果$i+1$层取过模,那么这一层的运算即使没取模也要标记为取过模,因为实际值一定取模了
4.如果$i+1$层取过模,那么快速幂里需要加上$\phi(p)$,反之$i+1$没取模一定不要加,不然答案是错的
5.接下来在快速幂里更新第i层计算的取模标记
#include <cstdio>
#include <cstring>
#include <algorithm>
#define NN 501000
#define MM 20001000
#define maxn 20000000
#define ll long long
#define uint unsigned int
#define ull unsigned long long
using namespace std; int n,m,g,r,root;
int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int use[MM],pr[],phi[MM],cnt;
void Pre()
{
phi[]=;
for(int i=;i<=maxn;i++)
{
if(!use[i]) pr[++cnt]=i,phi[i]=i-;
for(int j=;j<=cnt&&i*pr[j]<=maxn;j++){
use[i*pr[j]]=;
if(i%pr[j]) phi[i*pr[j]]=phi[i]*phi[pr[j]];
else {phi[i*pr[j]]=phi[i]*pr[j];break;}
}
}
}
struct Seg{
ull val[NN<<],tag[NN<<];
void pushdown(int rt){
if(!tag[rt]) return;
val[rt<<]+=tag[rt],val[rt<<|]+=tag[rt];
tag[rt<<]+=tag[rt],tag[rt<<|]+=tag[rt];
tag[rt]=;
}
void update(int L,int R,int l,int r,int rt,int w)
{
if(L<=l&&r<=R){tag[rt]+=w,val[rt]+=w;return;}
int mid=(l+r)>>;pushdown(rt);
if(L<=mid) update(L,R,l,mid,rt<<,w);
if(R>mid) update(L,R,mid+,r,rt<<|,w);
//pushup(rt);
}
ull query(int x,int l,int r,int rt)
{
if(l==r) return val[rt];
int mid=(l+r)>>;pushdown(rt);
if(x<=mid) return query(x,l,mid,rt<<);
else return query(x,mid+,r,rt<<|);
//pushup(rt);
}
}s;
ull qpow(ull x,ull y,int p,int &fl)
{
ull ans=;
if(y==) return ;
if(x>=p) x%=p,fl=;
while(y){
if(y&){
if(ans*x>=p)
ans=ans*x%p,fl=;
else ans=ans*x;
}
if(x*x>=p)
x=x*x%p,fl=;
else x=x*x;
y>>=;
}return ans;
}
ull euler(int i,int ma,int p,int &fl)
{
ull ai=s.query(i,,n,);
if(p==) {fl=;return ;}
if(ai>=p) fl=;
if(ai%p==) return ;
if(ai==) {fl=;return ;}
int o=;ai%=p;
if(i==ma) return ai;
ull ans=euler(i+,ma,phi[p],o);
if(o==) fl=;
/*if(ans==0){
if(o){
if(ai%p==0) {return 0;}
else return qpow(ai,ans+phi[p],p,fl);
}else{
return 1;
}
}else{
if(o) return qpow(ai,ans+phi[p],p,fl);
else return qpow(ai,ans,p,fl);
}*/
if(ans==&&o&&ai==) return ;
else if(o) return qpow(ai,ans+phi[p],p,fl);
else return qpow(ai,ans,p,fl);
} int main()
{
//freopen("t2.in","r",stdin);
//freopen("testdata.in","r",stdin);
//freopen("a.out","w",stdout);
int fl,x,y,z;
scanf("%d%d",&n,&m);
Pre();
for(int i=;i<=n;i++)
x=gint(),s.update(i,i,,n,,x);
for(int i=;i<=m;i++)
{
fl=gint(),x=gint(),y=gint(),z=gint();
if(fl==){
s.update(x,y,,n,,z);
}else{
int fl=;
printf("%llu\n",euler(x,y,z,fl));
}
}
return ;
}
BZOJ 5394 [Ynoi2016]炸脖龙 (线段树+拓展欧拉定理)的更多相关文章
- [洛谷P4118][Ynoi2016]炸脖龙I([洛谷P3934]Nephren Ruq Insania)
题目大意:有$n$个数,每个数为$s_i$,两个操作: $1\;l\;r\;x:$表示将区间$[l,r]$内的数加上$x$ $2\;l\;r\;p:$表示求$s_l^{s_{l+1}^{^{s_{l+ ...
- BZOJ5394: [Ynoi2016]炸脖龙(欧拉广义降幂)
就是让你求这个: 传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5394 解题思路: NOIP2018后第一道题,感觉非常像那个上帝与集合的 ...
- P4118 [Ynoi2016]炸脖龙I
思路:扩展欧拉定理 提交:\(\geq5\)次 错因:快速幂时刚开始没有判断\(a\)是否大于\(p\) 题解: 用树状数组维护差分,查询时暴力从左端点的第一个数向右端点递归,若递归时发现指数变为\( ...
- Luogu P4118 [Ynoi2016]炸脖龙I
题目 首先考虑没有修改的情况.显然直接暴力扩展欧拉定理就行了,单次复杂度为\(O(\log p)\)的. 现在有了修改,我们可以树状数组维护差分数组,然后\(O(\log n)\)地单次查询单点值. ...
- 【BZOJ4869】相逢是问候(线段树,欧拉定理)
[BZOJ4869]相逢是问候(线段树,欧拉定理) 题面 BZOJ 题解 根据欧拉定理递归计算(类似上帝与集合的正确用法) 所以我们可以用线段树维护区间最少的被更新的多少次 如果超过了\(\varph ...
- [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】
题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...
- [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】
题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过 1018,即使它在 ProblemSet 的第一页 ...
- [BZOJ 3888] [Usaco2015 Jan] Stampede 【线段树】
题目链接:BZOJ - 3888 题目分析 首先,计算出每个线段在 x 坐标 0 处出现的时间开始点和结束点,就转成了时间轴上的线段. 然后就是看每条线段是否被 y 比它小的线段完全覆盖了.注意求出的 ...
- [BZOJ 3747] [POI 2015] Kinoman【线段树】
Problem Link : BZOJ 3747 题解:ZYF-ZYF 神犇的题解 解题的大致思路是,当区间的右端点向右移动一格时,只有两个区间的左端点对应的答案发生了变化. 从 f[i] + 1 到 ...
随机推荐
- Unity 退出游戏 方法
Application.Quit(); 嗯,没错,这篇就这么短.
- WiFi无线连接过程中有哪几个主要步骤?
WiFi无线连接过程中有哪几个主要步骤?[1]在使用WIFI功能时,经常性的操作是打开手机上的WiFi设备,搜索到心目中的热点,输入密码,联网成功,成功上网.这个看似简单的过程,背后却是隐藏着大量的无 ...
- (转)JobTracker和TaskTracker概述
一 概述: (1)Hadoop MapReduce采用Master/Slave结构. *Master:是整个集群的唯一的全局管理者,功能包括:作业管理.状态监控和任务调度等,即MapReduce中的J ...
- 利用after和before伪元素在文字两边写横线
示例: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- composer install或者update 出错
composer install或者update 出错Your requirements could not be resolved to an installable set of package ...
- C++操作符重载总结operator(小结 更新ing)
操作符重载一个原则是:被操作的数据类型中 至少有一个是自定义的类型(使用class定义类),如果被操作的变量都是基本类型,那么就不能定义操作符重载. 1.如果重载了new,则必须重载delete,因为 ...
- 紫书 例题8-1 UVa 120(构造法)
#include<cstdio> #include<iostream> #include<sstream> #include<algorithm> #d ...
- a[i++]=a 数组下标自加优先问题
a[i++]=a 即是: a[i] = a;i ++;先把a赋值给数组a下标为 i 的 元素把 i 自加 1 :即指向下一个元素 =================================== ...
- linux内核(五)虚拟文件系统
虚拟文件系统(VFS)是linux内核和具体I/O设备之间的封装的一层共通访问接口,通过这层接口,linux内核可以以同一的方式访问各种I/O设备. 虚拟文件系统本身是linux内核的一部分,是纯软件 ...
- NYIST 1107 最高的奖励
最高的奖励 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 请问:挖掘机技术哪家强?AC了告诉你! 给你N(N<=3*10^4)个任务,每个任务有一个截止完成时 ...