bzoj4373:算数天才与等差数列

算术天才⑨非常喜欢和等差数列玩耍。
有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。
他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
当然,他还会不断修改其中的某一项。
为了不被他鄙视,你必须要快速并正确地回答完所有问题。
注意:只有一个数的数列也是等差数列。

第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
第二行包含n个整数,依次表示序列中的每个数a[i](0<=a[i]<=10^9)。
接下来m行,每行一开始为一个数op,
若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。
若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。
在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。

这道题用检验累加和/平方和的方式水过了。。最后发现是质数太大,乘起来溢出了。。。。。。

调了我三天(蠢哭了)

  1 #include <cstdio>
  2 #include <utility>
  3 using namespace std;
  4 typedef long long LL;
  5 typedef pair<LL, LL> ll;
  6 //#define debug
  7 
  8 #ifdef debug
  9 const LL maxn=105, prime=1e9+7;
 10 #else
 11 const LL maxn=3e5+5, prime=1e9+7;
 12 #endif
 13 LL n, m, cntyes;
 14 //可以捆绑♂到一起,这样查询更新都方便
 15 LL seg_sum[maxn*4], seg_sqr[maxn*4], maxm[maxn*4], minm[maxn*4];
 16 LL flag, *seg, POS, L, R, v;
 17 
 18 inline LL max(LL x, LL y) { return x<y?y:x; }
 19 inline LL min(LL x, LL y) { return x<y?x:y; }
 20 inline void swap(LL &x, LL &y) { LL t=x; x=y; y=t; }
 21 
 22 void modify(LL now, LL l, LL r){ //其实可以四个一起修改
 23     if (l>r||l>POS||r<POS) return;
 24     if (l==r) {
 25         if (flag==1) maxm[now]=minm[now]=v;
 26         if (flag==2) seg_sum[now]=v, seg_sqr[now]=v*v%prime;
 27         return;
 28     }
 29     LL mid=(l+r)>>1;
 30     modify(now<<1, l, mid); modify(now<<1|1, mid+1, r);
 31     if (flag==1){
 32         maxm[now]=max(maxm[now<<1], maxm[now<<1|1]);
 33         minm[now]=min(minm[now<<1], minm[now<<1|1]);
 34     }
 35     if (flag==2) {
 36         seg_sum[now]=(seg_sum[now<<1]+seg_sum[now<<1|1])%prime;
 37         seg_sqr[now]=(seg_sqr[now<<1]+seg_sqr[now<<1|1])%prime;
 38     }
 39 }
 40 
 41 ll query(LL now, LL l, LL r){ //其实可以四个一起查询
 42     if (l>r||l>R||r<L){
 43         if (flag==1) return make_pair(1e9, 0);
 44         if (flag==2) return make_pair(0, 0);
 45     }
 46     if (l>=L&&r<=R){
 47         if (flag==1)
 48             return make_pair(minm[now], maxm[now]);
 49         if (flag==2)
 50             return make_pair(seg_sum[now], seg_sqr[now]);
 51     }
 52     LL mid=(l+r)>>1;
 53     ll pair1, pair2;
 54     pair1=query(now<<1, l, mid); pair2=query(now<<1|1, mid+1, r);
 55     if (flag==1)
 56         return make_pair(min(pair1.first, pair2.first),
 57                          max(pair1.second, pair2.second));
 58     if (flag==2)
 59         return make_pair((pair1.first+pair2.first)%prime,
 60                          (pair1.second+pair2.second)%prime);
 61     return make_pair(-1, -1);
 62 }
 63 
 64 int main(){
 65     scanf("%lld%lld", &n, &m);
 66     LL value;
 67     for (LL i=1; i<=n; ++i){
 68         scanf("%lld", &value);
 69         flag=1, POS=i, v=value;
 70         modify(1, 1, n);
 71         flag=2, POS=i, v=value;
 72         modify(1, 1, n);
 73     }
 74     LL op, x, y, l, r, k;
 75     for (LL i=0; i<m; ++i){
 76         scanf("%lld", &op);
 77         if (op==1){
 78             scanf("%lld%lld", &x, &y);
 79             x^=cntyes, y^=cntyes;
 80             flag=1, POS=x, v=y;
 81             modify(1, 1, n);
 82             flag=2;
 83             modify(1, 1, n);
 84         }
 85         LL h, t, qsum, qsqr, vecsum, vecsqr;
 86         if (op==2){
 87             scanf("%lld%lld%lld", &l, &r, &k);
 88             l^=cntyes, r^=cntyes, k^=cntyes;
 89             if (l==r){
 90                 ++cntyes;
 91                 printf("Yes\n");
 92                 continue;
 93             }
 94             if (l>r) swap(l, r);
 95             //查询最大最小值
 96             flag=1, L=l, R=r;
 97             ll re=query(1, 1, n);
 98             //h:等差队列最小值,t:等差队列最大值
 99             h=re.first, t=re.second;
100             if (k*(r-l)!=t-h){
101                 printf("No\n"); continue;
102             }
103             //查询区间和
104             flag=2, L=l, R=r;
105             re=query(1, 1, n);
106             qsum=re.first, qsqr=re.second;
107             vecsum=(h+t)*(r-l+1)/2;
108             vecsum%=prime; //忘记模了。。
109             LL n=r-l+1;
110             //计算等差数列的平方和 h:a1 k:d l=r时要特判!!!
111             vecsqr=(h*h%prime*n%prime+
112                     (0+n-1)*n%prime*h%prime*k%prime)%prime+
113                     k*k%prime*((n-1)*n%prime*(2*n-1)/6%prime);
114             vecsqr%=prime;
115             if (qsum==vecsum&&qsqr==vecsqr){
116                 ++cntyes;
117                 printf("Yes\n");
118             }
119             else printf("No\n");
120         }
121     }
122     return 0;
123 }

 

posted @ 2017-09-11 07:23  pechpo  阅读(328)  评论(0编辑  收藏  举报