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 到 ...
随机推荐
- hdu 1240(三维广搜)
题意: 有一个n*n*n的三维空间. 给你起始坐标和终点坐标.要你从起点到终点,问最少需要多少步走出去.如果走不出去则输出"NO ROUTE". 空间中 'O' 表示这个点可以走, ...
- Pyhton学习——Day31
# 服务端和接收端的send和reve没有任何关系,只与协议之间有关系# 应用程序产生的数据一定会交给操作系统,并由操作系统往外发送# 发送端什么时候会清空自己的内存?# 收到接收端的ACK响应以后才 ...
- tcpsock.v2 与 ecocache
因为很不满意 tcpsock 的设计与实现,及有意专为譬如游戏服务器端开发设计一套 TCP 网络库,所以年初即有了 tcpsock.v2 的开发计划,于是粗略整理出了以下几条目标计划: 1) TcpC ...
- Vue学习之路第三篇:插值表达式和v-text的区别
上一篇说到插值表达式有一个问题: 页面频繁刷新或者网速加载很慢的时候,页面会先出现“{{ msg }}”,再一闪而过出现真实的数据. 对于这个问题Vue给予了解决办法,看具体事例. <div i ...
- Layui Excle/csv数据导出
官方文档的数据是这样的 依赖 Layui 2.4版本以上 layui.use([ 'table'], function(){ var table=layui.table; table.exportFi ...
- 浅谈密码加SALT原理
我们知道,如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例如MD5密码破解网站),得到某用户的密码. 加Salt可以一定程度上解决这一问题.所谓加Salt方法, ...
- 可编辑div,将光标定位到文本之后
类似qq回复一样,某人评论之后,在对评论进行回复之后,将光标定位到文本之后: function set_focus() { el=document.getElementById('guestbook_ ...
- 练练脑,继续过Hard题目
http://www.cnblogs.com/charlesblc/p/6384132.html 继续过Hard模式的题目吧. # Title Editorial Acceptance Diffi ...
- window8.1 CenterOS 双系统
window8.1 CenterOS 双系统 学习了: http://blog.csdn.net/ac_hell/article/details/53436890 https://jingyan.ba ...
- [Python + Unit Testing] Write Your First Python Unit Test with pytest
In this lesson you will create a new project with a virtual environment and write your first unit te ...