bzoj 4373: 算术天才⑨与等差数列 (线段树||线段树+set)
来源:互联网 发布:紫猫编程学院全套教程 编辑:程序博客网 时间:2024/06/08 06:41
题目描述
传送门
题目大意:
操作1:x,y,将a[x]修改成y
操作2:l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
题解1
等差数列求和公式
如果单纯的维护区间最小值最大值以及区间和,利用等差数列求和公式计算的话出错的概率会非常高,所以我们再维护一下区间平方和
平方和公式
平方和可能会炸long long ,所以用unsigned long long 自然溢出即可。
代码1
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define LL unsigned long long #define N 300013using namespace std;struct data{ LL sum,mn,mx,squ;}tr[N*4];int n,m,a[N];void update(data &now,data l,data r){ now.sum=l.sum+r.sum; now.squ=l.squ+r.squ; now.mn=min(l.mn,r.mn); now.mx=max(l.mx,r.mx);}void build(int now,int l,int r){ if (l==r) { tr[now].sum=tr[now].mn=tr[now].mx=(LL)a[l]; tr[now].squ=(LL)a[l]*a[l]; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(tr[now],tr[now<<1],tr[now<<1|1]);}void pointchange(int now,int l,int r,int x,LL v){ if (l==r) { tr[now].sum=tr[now].mn=tr[now].mx=v; tr[now].squ=v*v; return; } int mid=(l+r)/2; if (x<=mid) pointchange(now<<1,l,mid,x,v); else pointchange(now<<1|1,mid+1,r,x,v); update(tr[now],tr[now<<1],tr[now<<1|1]);}data query(int now,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return tr[now]; int mid=(l+r)/2; bool pd=false; data ans; if (ll<=mid) ans=query(now<<1,l,mid,ll,rr),pd=true; if (rr>mid) { if (pd) update(ans,ans,query(now<<1|1,mid+1,r,ll,rr)); else ans=query(now<<1|1,mid+1,r,ll,rr); } return ans;}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); int cnt=0; for (int i=1;i<=m;i++){ int opt,l,r,x,y,k; scanf("%d",&opt); if (opt==1) { scanf("%d%d",&x,&y); x^=cnt; y^=cnt; pointchange(1,1,n,x,y); } else { scanf("%d%d%d",&l,&r,&k); l^=cnt; r^=cnt; k^=cnt; LL k1=k; data t=query(1,1,n,l,r); LL len=(LL)(r-l+1); LL f=(LL)len*(len-1)*(2*len-1)/6; LL g=(len-1)*len; LL sum=(LL)(t.mx+t.mn)*len/2; LL squ=(LL)t.mn*t.mn*len+(LL)k1*k1*f+(LL)g*t.mn*k1; if (t.sum==sum&&t.squ==squ) printf("Yes\n"),cnt++; else printf("No\n"); } }}
题解2
设
关键是如何判断区间中没有重复的数。
对于每个位置的数x,维护pre表示x前一次出现的位置。
注意k=0的时候需要特判一下。
代码2
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<map>#include<set>#define N 300013#define LL long long using namespace std;struct data{ int gcd,pre,mx,mn; LL sum;}tr[N*4];map<int,int> mp;set<int> T[N*2];int n,m,a[N],b[N],c[N],cnt;int gcd(int x,int y){ if (x==0||y==0) return 0; int r; while (y) { r=x%y; x=y; y=r; } return x;}void update(data &now,data l,data r){ now.gcd=gcd(l.gcd,r.gcd); now.pre=max(l.pre,r.pre); now.mn=min(l.mn,r.mn); now.mx=max(l.mx,r.mx); now.sum=l.sum+r.sum;}void build(int now,int l,int r){ if (l==r) { tr[now].pre=b[l]; tr[now].sum=a[l]; tr[now].mx=tr[now].mn=a[l]; tr[now].gcd=c[l]; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(tr[now],tr[now<<1],tr[now<<1|1]);}void change(int now,int l,int r,int x){ if (l==r) { tr[now].pre=b[l]; tr[now].sum=a[l]; tr[now].mx=tr[now].mn=a[l]; tr[now].gcd=c[l]; return; } int mid=(l+r)/2; if (x<=mid) change(now<<1,l,mid,x); else change(now<<1|1,mid+1,r,x); update(tr[now],tr[now<<1],tr[now<<1|1]);}data query(int now,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return tr[now]; int mid=(l+r)/2; bool pd=false; data ans; if (ll<=mid) ans=query(now<<1,l,mid,ll,rr),pd=true; if (rr>mid) { if (pd) update(ans,ans,query(now<<1|1,mid+1,r,ll,rr)); else ans=query(now<<1|1,mid+1,r,ll,rr); } return ans;}int main(){ freopen("a.in","r",stdin);// freopen("my.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); if (!mp[a[i]]) mp[a[i]]=++cnt,T[cnt].insert(0),T[cnt].insert(N); T[mp[a[i]]].insert(i); b[i]=*--T[mp[a[i]]].find(i); } for (int i=2;i<=n;i++) c[i]=abs(a[i]-a[i-1]); build(1,1,n); int ans=0; for (int i=1;i<=m;i++){ int opt,x,y,l,r,k; scanf("%d",&opt); if (opt==1) { scanf("%d%d",&x,&y); x^=ans; y^=ans; int pre=*--T[mp[a[x]]].find(x); int nxt=*++T[mp[a[x]]].find(x); if (nxt!=N)b[nxt]=pre,change(1,1,n,nxt); T[mp[a[x]]].erase(x); if (!mp[y]) mp[y]=++cnt,T[cnt].insert(0),T[cnt].insert(N); T[mp[y]].insert(x); pre=*--T[mp[y]].find(x); nxt=*++T[mp[y]].find(x); b[x]=pre; a[x]=y; c[x]=abs(a[x]-a[x-1]); change(1,1,n,x); b[nxt]=x; change(1,1,n,nxt); if (x+1<=n) c[x+1]=abs(a[x+1]-a[x]),change(1,1,n,x+1); } else { scanf("%d%d%d",&l,&r,&k); l^=ans; r^=ans; k^=ans; data t=query(1,1,n,l,r); data t1=query(1,1,n,l+1,r); if (k==0) { if (t.mx==t.mn) printf("Yes\n"),ans++; else printf("No\n"); continue; } if (l==r) { printf("Yes\n"); ans++; continue; } LL len=r-l+1; if (t1.gcd==k&&(t.mx-t.mn)/(r-l)==k&&(t.mx-t.mn)%(r-l)==0&&t.pre<l) printf("Yes\n"),ans++; else printf("No\n"); } }}
阅读全文
0 0
- bzoj 4373: 算术天才⑨与等差数列 (线段树||线段树+set)
- BZOJ 4373(算术天才⑨与等差数列-线段树+hash)
- BZOJ 4373 算术天才⑨与等差数列 [线段树]
- [BZOJ]4373: 算术天才⑨与等差数列 线段树+hash
- 【线段树】BZOJ4373算术天才与等差数列
- 【线段树】BZOJ4373算术天才与等差数列
- 线段树 bzoj4373 算术天才⑨与等差数列
- BZOJ4373: 算术天才⑨与等差数列 线段树
- [BZOJ4373][线段树]算术天才⑨与等差数列
- [BZOJ4373算术天才⑨与等差数列] 线段树
- bzoj 4373: 算术天才⑨与等差数列
- BZOJ 4373 算术天才⑨与等差数列
- bzoj 4373: 算术天才⑨与等差数列
- [bzoj] 4373算术天才⑨与等差数列
- BZOJ 4373: 算术天才⑨与等差数列
- bzoj 4373: 算术天才⑨与等差数列
- 4373: 算术天才⑨与等差数列
- bzoj 1558: [JSOI2009]等差数列 (线段树)
- USACO之 skidesign
- Android.mk文件详解
- python库地址
- 第7章 查询数据
- [unity&独立游戏]多人游戏插件
- bzoj 4373: 算术天才⑨与等差数列 (线段树||线段树+set)
- HBase RowKey
- Python的namedtuple使用详解
- UVa 116
- x86-64 下函数调用及栈帧原理
- Windows与Ubuntu16.04文件传输
- windows录音程序简单解析
- linux上配置开发环境
- qt 时钟绘制