mdzz,这道题重构了4遍,花了一个晚上。。。


满足等差数列的条件:

1. 假设min是区间最小值,max是区间最大值,那么 max-min+k(r−l)

2. 区间相邻两个数之差的绝对值的gcd=k

3. 区间没有重复的数

前两个条件直接线段树就好啦;而第三个条件:对于每个权值开个set,值为位置(离散化)然后维护一个pp[i],表示当前a[i]这个值,在i前面最后一次出现的位置。

那么满足第3个条件,当且仅当区间[l,r]的 max { pre[ i ] } ( l <= i <= r ) 小于l,这个也是用线段树维护。

最后看修改操作:在set上找前一个数,后一个数,然后修改相应的pre值。

#include<cstdio>
#include<iostream>
#include<map>
#include<set>
#define R register int
#define pc(x) putchar(x)
#define ls (tr<<1)
#define rs (tr<<1|1)
using namespace std;
const int N=,M=;
int n,m,cnt,num,mod,G,mmn,mmx;
int mn[M],mx[M],pp[M],gg[M],a[N],b[N],pos[N],d[N];
bool flg;
map<int,int>mp;
set<int>s[N<<];
set<int>::iterator pre,nxt;
inline int g() {
R ret=; register char ch; while(!isdigit(ch=getchar())) ;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret;
}
inline int abs(int a) {return a>?a:-a;}
inline int gcd(int a,int b) {return b?gcd(b,a%b):a;}
inline int calc(int x) { R ret;
if(mp.find(x)==mp.end()) ret=mp[x]=++cnt; else return mp[x];
s[ret].insert(),s[ret].insert(n+); return ret;
}
inline void build(int tr,int l,int r) {
if(l==r) {mn[tr]=mx[tr]=a[l]; pp[tr]=pos[l]; gg[tr]=d[l]; return ;}
R md=(l+r)>>; build(ls,l,md),build(rs,md+,r);
mn[tr]=min(mn[ls],mn[rs]),mx[tr]=max(mx[ls],mx[rs]);
pp[tr]=max(pp[ls],pp[rs]),gg[tr]=gcd(gg[ls],gg[rs]);
}
inline void updatep(int tr,int l,int r,int pos,int p) {
if(l==r) {pp[tr]=p; return ;} R md=(l+r)>>;
if(pos<=md) updatep(ls,l,md,pos,p); else updatep(rs,md+,r,pos,p);
pp[tr]=max(pp[ls],pp[rs]);
}
inline void updateg(int tr,int l,int r,int pos,int G) {
if(l==r) {gg[tr]=G; return;} R md=(l+r)>>;
if(pos<=md) updateg(ls,l,md,pos,G); else updateg(rs,md+,r,pos,G);
gg[tr]=gcd(gg[ls],gg[rs]);
}
inline void update(int tr,int l,int r,int pos,int inc,int pre) {
if(l==r) {mn[tr]=mx[tr]=inc; pp[tr]=pre; return ;} R md=(l+r)>>;
if(pos<=md) update(ls,l,md,pos,inc,pre); else update(rs,md+,r,pos,inc,pre);
mn[tr]=min(mn[ls],mn[rs]),mx[tr]=max(mx[ls],mx[rs]),pp[tr]=max(pp[ls],pp[rs]);
}
inline void ask(int tr,int l,int r,int LL,int RR) {
if(LL<=l&&r<=RR) {mmn=min(mmn,mn[tr]),mmx=max(mmx,mx[tr]); if(pp[tr]>=LL) flg=; return;}
R md=(l+r)>>; if(LL<=md) ask(ls,l,md,LL,RR); if(RR>md) ask(rs,md+,r,LL,RR);
}
inline void askg(int tr,int l,int r,int LL,int RR) {
if(LL<=l&&r<=RR) {G=gcd(gg[tr],G); return ;} R md=(l+r)>>;
if(LL<=md) askg(ls,l,md,LL,RR); if(RR>md) askg(rs,md+,r,LL,RR);
}
inline bool judge(int l,int r) {
if(l==r) return true; flg=false,mmn=0x3f3f3f3f,mmx=G=;
ask(,,n,l,r); if(!mod) return mmx==mmn;
if(flg) return false;
if(mmx-mmn!=1ll*(r-l)*mod) return false;
askg(,,n,l,r-); return G%mod==;
}
signed main() {
n=g(),m=g();
for(R i=;i<=n;i++) {
a[i]=g(); s[b[i]=calc(a[i])].insert(i);
pre=s[b[i]].find(i); pos[i]=*(--pre);
} for(R i=;i<n;i++) d[i]=abs(a[i]-a[i+]); build(,,n);
for(R i=;i<=m;++i) { R k=g(),l=g()^num,r=g()^num;
if(k&) {
pre=nxt=s[b[l]].find(l); pre--,nxt++;
if(*nxt<n) updatep(,,n,*nxt,*pre);
s[b[l]].erase(l),b[l]=calc(r),s[b[l]].insert(l);
pre=nxt=s[b[l]].find(l); pre--,nxt++;
if(*nxt<n) updatep(,,n,*nxt,l); update(,,n,l,a[l]=r,*pre);
if(l>) updateg(,,n,l-,abs(a[l-]-r));
if(l<n) updateg(,,n,l,abs(r-a[l+]));
} else mod=g()^num,judge(l,r)?(++num,pc('Y'),pc('e'),pc('s')):(pc('N'),pc('o')),pc('\n');
}
}

2019.04.22 这道题让我想扔掉OI。。。气死我了。。。QAQ

BZOJ 4373 算术天才⑨与等差数列 线段树+set(恶心死我了)的更多相关文章

  1. bzoj 4373 算术天才⑨与等差数列——线段树+set

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373 能形成公差为k的等差数列的条件:mx-mn=k*(r-l) && 差分 ...

  2. BZOJ 4373算术天才⑨与等差数列(线段树)

    题意:给你一个长度为n的序列,有m个操作,写一个程序支持以下两个操作: 1. 修改一个值 2. 给出三个数l,r,k, 询问:如果把区间[l,r]的数从小到大排序,能否形成公差为k的等差数列. n,m ...

  3. BZOJ 4373: 算术天才⑨与等差数列 线段树

    Description 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能 ...

  4. bzoj 4373 算术天才⑨与等差数列

    4373: 算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MBhttp://www.lydsy.com/JudgeOnline/problem.ph ...

  5. 【BZOJ4373】算术天才⑨与等差数列 [线段树]

    算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 算术天才⑨非常喜欢和等 ...

  6. 【BZOJ4373】算术天才⑨与等差数列 线段树+set

    [BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k, ...

  7. bzoj 4373: 算术天才⑨与等差数列 hash

    题目链接 题目大意:  给你n个数, 给两种操作, 一种给你l, r, k,问你[l, r]区间里的数排序后能否构成一个公差为k的等差数列. 另一种是将位置x的数变为y. 强制在线. 可以用hash来 ...

  8. [BZOJ4373]算术天才⑨与等差数列(线段树)

    [l,r]中所有数排序后能构成公差为k的等差数列,当且仅当: 1.区间中最大数-最小数=k*(r-l) 2.k能整除区间中任意两个相邻数之差,即k | gcd(a[l+1]-a[l],a[l+2]-a ...

  9. bzoj4373 算术天才⑨与等差数列——线段树+set

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373 一个区间有以 k 为公差的数列,有3个条件: 1.区间 mx - mn = (r-l) ...

随机推荐

  1. DAY13-前端之BOM和DOM

    前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些交互,我们需要继续学习BOM和DO ...

  2. session详解&和cookie的区别

    session简介 1. 定义 session用来保存会话数据, 将数据保存到服务器中. 2. 作用 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),一个浏览器独占一 ...

  3. Android按钮单击事件的四种常用写法

    这篇文章主要介绍了Android按钮单击事件的四种常用写法总结,比较了常见的四种写法的优劣,有不错的参考借鉴价值,需要的朋友可以参考下 很多学习Android程序设计的人都会发现每个人对代码的写法都有 ...

  4. day70-oracle 12-触发器

    查询是没有触发器的.trigger是一个数据库的对象.PL/SQL程序是在我插入之前执行还是在插入之后执行?触发器类似于java中的监听器. 监听插入操作,执行一段PLSQL程序. 禁止在非工作时间插 ...

  5. SQL serve 数据库--视图、事物、分离附加、备份还原

    视图是数据库中的一种虚拟表,与真实的表一样,视图包含一系列带有名称的行和列数据.行和列数据用来自定义视图的查询所引用的表,并且在引用视图时动态生成.  视图只能用来查询,不能增删改:不允许出现重复列 ...

  6. Linux共享对象之编译参数 -fPIC

    转载自:https://www.cnblogs.com/cswuyg/p/3830703.html     在Linux系统中,动态链接文件称为动态共享对象(DSO,Dynamic Shared Ob ...

  7. 共享库so

    so文件在linux中为共享库,与windows下的dll类似. so文件中的函数可供多个进程调用,最大可能的提供二进制代码的复用. 共享库可以使代码的维护工作大大简化,当修正了一些错误或者添加了新特 ...

  8. 十三周作业—使用Metaspoit攻击MS08-067

    操作过程及结果如下:

  9. [译]Javascript数列的push和pop方法

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  10. libsvm使用简介

    libsvm是support vector machine的一种开源实现,采用了smo算法.源代码编写有独到之处,值得一睹. 常用结构 svm_node结构 定义了构成输入特征向量的元素,index为 ...