题目大意:给你一个长度为$n$的序列$A_i$,有$q$次操作,每次操作为以下三种之一:

询问区间的$F_M(A_i)$的最大公约数。

区间翻转,区间加一个正数。

我们定义$gcd(0,0)=0$,且$F_M(A_i)$为在一个$M$个点的无向完全图中从第一个点开始走$k$步后回到第一个点的方案数。

数据范围:$n,q≤10^5$,$0≤A_i≤10^8$,$2≤M≤10^9$。

我们先考虑下如何求$F_M(x)$。

经过打表(大雾),我们发现:

若$x$为偶数,则$F_M(x)=M\times(F_M(x-1)+1)$

若$x$为奇数,则$F_M(x)=M\times(F_M(x-1)-1)$

特别地,$F_M(0)=1$,$F_M(1)=0$

我们显然可以$O(2\times 10^8)$预处理或者直接矩阵快速幂计算。

继续打表,我们发现:$gcd(F_M(x-1),F_M(y-1))=F_M(gcd(x-1,y-1))$,感兴趣的同学可以证明一下(反正我不会)

我们发现,如果询问的区间中存在数字0,则这个区间的GCD显然为1

考虑到要资瓷区间翻转,区间查询0的个数,区间抹去0,对于这部分我们需要单独开一棵splay来维护。

考虑维护>1部分的数。

我们先不考虑翻转的情况。

我们将差分后的数列丢入一棵splay中,每个节点维护整棵子树内的权值和,还有子树内的GCD

我们需要查询区间$[l,r]$的$GCD$时,我们只需要查询$[l+1,r]$的区间GCD,然后再和第$l$个位置的值求GCD即可输出。

原因显然

考虑翻转区间$[l,r]$的情况:不难发现受到影响的区间为$[l,r+1]$。

然后,经过冷静分析(大雾),我们发现翻转前后有这样的性质:

1,第$l$个位置的查分值和第$r+1$个位置的差分值需要单独更新。

2,区间$[l+1,r]$内的差分值等于原区间$[l+1,r]$内的差分值翻转再取相反数。

上面这张图是一个例子,证明显然。

然后,我们开几个标记打一下就可以了。

然后就没有然后了,注意细节

时间复杂度:$O(n\log^2\ n)$

 #include<bits/stdc++.h>
#define M 200005
#define MOD 323232323
#define L long long
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
using namespace std; int GCD(int x,int y){return __gcd(abs(x),abs(y));} struct mat{
L a[][]; mat(){memset(a,,sizeof(a));}
void danwei(){a[][]=a[][]=a[][]=;}
friend mat operator *(mat a,mat b){
mat c;
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%MOD;
return c;
}
friend mat operator ^(mat x,int b){
mat ans; ans.danwei();
while(b){
if(b&) ans=ans*x;
x=x*x; b>>=;
}
return ans;
}
};
L P;
L getans(int n){
if(n==) return ;
mat a;
a.a[][]=a.a[][]=;
a.a[][]=P*P%MOD;
a.a[][]=(P-+MOD)%MOD;
a=a^(n-);
L res=a.a[][]*P%MOD;
if(n&) res=P*(res+)%MOD;
return res;
} namespace FF{
int siz[M]={},ch[M][]={},sum[M]={},tagf[M]={},val[M]={},rev[M]={},fa[M]={},use=; int root=;
void pushup(int x){
siz[x]=siz[lc(x)]+siz[rc(x)]+;
sum[x]=sum[lc(x)]+sum[rc(x)]+val[x];
}
void upd(int x){rev[x]^=; swap(lc(x),rc(x)); }
void cls(int x){tagf[x]=; sum[x]=val[x]=;}
void pushdown(int x){
if(rev[x]) upd(lc(x)),upd(rc(x)); rev[x]=;
if(tagf[x]) cls(lc(x)),cls(rc(x)); tagf[x]=;
}
void rotate(int x,int &k){
int y=fa[x],z=fa[y],l,r;
l=(ch[y][]!=x); r=l^;
if(y==k) k=x;
else{
if(lc(z)==y) ch[z][]=x;
else ch[z][]=x;
}
fa[y]=x; fa[x]=z; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
pushup(y); pushup(x);
}
void pud(int x,int k){if(x!=k) pud(fa[x],k); pushdown(x);} void splay(int x,int &k){
pud(x,k);
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if((lc(y)==x)==(lc(z)==y)) rotate(y,k);
else rotate(x,k);
}
rotate(x,k);
}
}
int insert(int x,int id,int zhi){
pushdown(x);
if(!x){x=++use; val[x]=zhi;}
else{
if(siz[lc(x)]+<=id) rc(x)=insert(rc(x),id-siz[lc(x)]-,zhi),fa[rc(x)]=x;
else lc(x)=insert(lc(x),id,zhi),fa[lc(x)]=x;
}
pushup(x); return x;
}
int find(int x,int k){
pushdown(x);
if(siz[lc(x)]+==k) return x;
if(siz[lc(x)]>=k) return find(lc(x),k);
return find(rc(x),k-siz[lc(x)]-);
}
void ins(int x,int k){
root=insert(root,k,x);
splay(use,root);
} int query(int x,int y){
int X=find(root,x),Y=find(root,y+);
splay(X,root); splay(Y,rc(root));
return sum[lc(Y)];
}
void updata(int x,int y){
int X=find(root,x),Y=find(root,y+);
splay(X,root); splay(Y,rc(root));
cls(lc(Y));
pushup(Y);
pushup(root);
}
void setrev(int x,int y){
int X=find(root,x),Y=find(root,y+);
splay(X,root); splay(Y,rc(root));
upd(lc(Y));
}
} int siz[M]={},ch[M][]={},gcd[M]={},sum[M]={},val[M]={},rev[M]={},fa[M]={},use=; int root=;
void pushup(int x){
siz[x]=siz[lc(x)]+siz[rc(x)]+;
sum[x]=sum[lc(x)]+sum[rc(x)]+val[x];
gcd[x]=GCD(GCD(gcd[lc(x)],gcd[rc(x)]),val[x]);
}
void upd(int x){rev[x]^=; swap(lc(x),rc(x)); sum[x]=-sum[x]; val[x]=-val[x];}
void pushdown(int x){if(rev[x]) upd(lc(x)),upd(rc(x)); rev[x]=;}
void rotate(int x,int &k){
int y=fa[x],z=fa[y],l,r;
l=(ch[y][]!=x); r=l^;
if(y==k) k=x;
else{
if(lc(z)==y) ch[z][]=x;
else ch[z][]=x;
}
fa[y]=x; fa[x]=z; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
pushup(y); pushup(x);
}
void pud(int x){if(x!=root) pud(fa[x]); pushdown(x);} void splay(int x,int &k){
pud(x);
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if((lc(y)==x)==(lc(z)==y)) rotate(y,k);
else rotate(x,k);
}
rotate(x,k);
}
}
int insert(int x,int id,int zhi){
pushdown(x);
if(!x){x=++use; val[x]=zhi;}
else{
if(siz[lc(x)]+<=id) rc(x)=insert(rc(x),id-siz[lc(x)]-,zhi),fa[rc(x)]=x;
else lc(x)=insert(lc(x),id,zhi),fa[lc(x)]=x;
}
pushup(x); return x;
}
int find(int x,int k){
pushdown(x);
if(siz[lc(x)]+==k) return x;
if(siz[lc(x)]>=k) return find(lc(x),k);
return find(rc(x),k-siz[lc(x)]-);
}
void ins(int x,int k){
root=insert(root,k,x);
splay(use,root);
}
void del(int k){
int x=find(root,k); splay(x,root);
int y=find(root,k+); lc(y)=lc(x);
fa[lc(x)]=y; fa[rc(x)]=; root=rc(x);
splay(y,root); } int getval(int id){
int x=find(root,id+);
splay(x,root);
return val[x]+sum[lc(x)];
}
int query(int x,int y){
if(x>y) return ;
int X=find(root,x),Y=find(root,y+);
splay(X,root);
splay(Y,rc(root));
return gcd[lc(Y)];
}
void updata(int id,int delta){
int x=find(root,id);
splay(x,root);
val[x]+=delta;
pushup(x);
} void setrev(int x,int y){
int X=find(root,x),Y=find(root,y+);
splay(X,root);
splay(Y,rc(root));
upd(lc(Y));
pushup(lc(Y));
splay(lc(Y),root);
} void setval(int x,int V){
int X=find(root,x+);
splay(X,root);
val[X]=V;
pushup(X);
} int n,m,a[M]={}; int main(){
ins(,); ins(,);
FF::ins(,); FF::ins(,);
int cas; scanf("%d",&cas);
scanf("%d%d%d",&P,&n,&m); P--;
for(int i=;i<=n;i++) scanf("%d",a+i),a[i]--; for(int i=;i<=n+;i++){
ins(a[i]-a[i-],i);
FF::ins(a[i]==-,i);
} while(m--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==){
int F=FF::query(x,y);
if(F) {printf("1\n"); continue;}
int ans=query(x+,y);
int las=getval(x);
printf("%lld\n",getans(GCD(las,ans)));
}
if(op==){
int k; scanf("%d",&k);
updata(x+,k);
updata(y+,-k);
FF::updata(x,y);
}
if(op==){
if(x==y) continue;
int Vl=getval(x-);
int VR=getval(y);
int Vr=getval(y+);
setrev(x+,y);
FF::setrev(x,y);
setval(x,VR-Vl); VR=getval(y); setval(y+,Vr-VR);
}
}
}

【2019北京集训2】Elephant 平衡树的更多相关文章

  1. 【2019北京集训测试赛(十三)】数据(sj) 冷静分析

    题目大意:给你一个代表区间$[1,n]$的线段树,问你随机访问区间$[1,n]$中的一个子区间,覆盖到的线段树节点个数的期望(需要乘上$\frac{n(n-1)}{2}$后输出). 数据范围:$n≤1 ...

  2. 【2019北京集训测试赛(七)】 操作 分治+FFT+生成函数

    题目大意:你有$n$个操作和一个初始为$0$的变量$x$. 第$i$个操作为:以$P_i$的概率给$x$加上$A_i$,剩下$1-P_i$的概率给$x$乘上$B_i$. 你袭击生成了一个长度为$n$的 ...

  3. 【2019北京集训六】路径(path) 二分+DP

    此题niubi! 题目大意:给你一颗n个点的点带权无根树,现在请您进行以下两步操作: 1,选择一个$[0,T]$之间的整数$C$,并令所有的点权$wi$变为$(wi+C)%MOD$ 2,选择若干条点不 ...

  4. 【2019北京集训3】逻辑 树剖+2-sat

    题目大意:有一颗有$m$个叶子节点的二叉树. 对于叶子节点$i$,$x[i]=(a[i]\ xor\ V_{p[i]})or(b[i]\ xor\ V_{q[i]})$ 对于非叶子节点$i$,$x[i ...

  5. 【2019北京集训2】duck 线段树优化建图+tarjan

    题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和 ...

  6. 【北京集训D2T3】tvt

    [北京集训D2T3]tvt \(n,q \le 1e9\) 题目分析: 首先需要对两条路径求交,对给出的四个点的6个lca进行分类讨论.易于发现路径的交就是这六个lca里面最深的两个所形成的链. 然后 ...

  7. (2016北京集训十)【xsy1528】azelso - 概率期望dp

    北京集训的题都是好题啊~~(于是我爆0了) 注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了... 设$f_i$表示从$i$出发不回到$i$ ...

  8. 【2017 北京集训 String 改编版】子串

    题意 你有一个字符串,你需要支持两种操作: 1:在字符串的末尾插入一个字符 \(c\) 2:询问当前字符串的 \([l,r]\) 子串中的不同子串个数 为了加大难度,操作会被加密(强制在线). \(n ...

  9. (2016北京集训十)【xsy1530】小Q与内存

    一道很有意思的神题~ 暴力平衡树的复杂度很对(并不),但是$2^{30}$的空间一脸屎 这题的正解是一个类似线段树的数据结构,我觉得很有创新性Orz 首先可以想到一种暴力就是用一个点代表一个区间,然后 ...

随机推荐

  1. sqlserver2017 重装过程中出现“无法找到数据库引擎启动句柄”错误的解决办法

    sqlserver数据库引擎修改账号名,详情参考:http://blog.51cto.com/djclouds/2089047?utm_source=oschina-app 在SQL Server安装 ...

  2. easyui 改变单元格背景颜色

    另外一种方法:https://www.cnblogs.com/raitorei/p/9989649.html easyui的datagrid改变整行颜色:https://www.cnblogs.com ...

  3. 156. Binary Tree Upside Down反转二叉树

    [抄题]: Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left nod ...

  4. [leetcode]90. Subsets II数组子集(有重)

    Given a collection of integers that might contain duplicates, nums, return all possible subsets (the ...

  5. Python - 最大公约数算法

    # Python 3.6 # 最大公约数,最大公因子 # Greatest Common Divisor # 辗转相除法 def gcd(num1: object, num2: object) -&g ...

  6. 判断是否是json

    转:https://blog.csdn.net/dy_smile/article/details/46739251 function isJson(obj) { var isjson = typeof ...

  7. epoll_wait会被系统中断唤醒

    今天,当一个程序在epoll_wait阻塞时,用strace跟踪了一下,结果epoll_wait就被EINTR唤醒了,并且返回-1: 所以,当epoll_wait返回-1时,需要判断errno是不是E ...

  8. .NET winform播放音频文件

    前提:最近要求做一个在winform端做一个音频文件播放的功能,至此,总结最近搜寻的相关资料. 一.微软提供了三种方式来播放音频文件 1.通过System.Media.SoundPlayer来播放 2 ...

  9. Python中删除easy_install安装的包

    网上查了一大圈,终于在官网上找到了.记一下,备忘...

  10. python之高阶函数

    1.函数的参数能接收变量 def calc(x): return x*x n = 10 print(calc(n)) #输出为100 2.变量指向函数 def calc(x): return x*x ...