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 到 ...
随机推荐
- Mac Technology Overview
[Mac Technology Overview]https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual ...
- prettier 与 eslint 对比
Linters have two categories of rules: 代码修正一般有两种规则: Formatting rules: eg: max-len, no-mixed-spaces-an ...
- org.xml.sax.SAXParseException: Failed to read schema document 的原因分析与解决方法
现象: org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema documen t 'http://www.s ...
- docker images镜像无法删除
删除所有容器: docker rm $(docker ps -aq) 删除镜像: docker rmi $(docker images -q) 如果有镜像无法删除,有可能更改了名字,用docker r ...
- [HDU1160]FatMouse's Speed
题目大意:读入一些数(每行读入$w[i],s[i]$为一组数),要求找到一个最长的序列,使得符合$w[m[1]] < w[m[2]] < ... < w[m[n]]$且$s[m[1] ...
- Linux磁盘分区--MBR分区
今天心情不高兴,做IT不容易被公司重视,一定要速度学会运营,成为一个高逼格的技术男. 今天我要熟练掌握linux系统分区的能力.大家都知道,linux系统分区有两种分区格式:GTP和MBR. MBR作 ...
- Django REST Framework 序列化和校验 知识点
DRF序列化 Django ORM对象 --> JSON格式的数据 序列化 JSON格式的数据 --> Django ORM数据 反序列化 需要两个工具: from rest_framew ...
- Java并发和多线程2:3种方式实现数组求和
本篇演示3个数组求和的例子. 例子1:单线程例子2:多线程,同步求和(如果没有计算完成,会阻塞)例子3:多线程,异步求和(先累加已经完成的计算结果) 例子1-代码 package cn.fansuni ...
- CORS与JSONP的区别
CORS与JSONP: a. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求. b. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSON ...
- JavaScript 的对象继承方式,有几种写法?
JavaScript 的对象继承方式,有几种写法? 一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Pa ...