P5278 算术天才⑨与等差数列

Problem

给一个序列,要求支持2种操作:

  • 单点修改
  • 查询\(a_l \cdots a_r\)从小到大排序是否是一个公差为\(k\)的等差数列
    \(n,q,k \le 3 \times 10^5\)

Solution

看见题目,感觉正解不太会,想通过多种等差数列的限制乱搞做题。
第一个想到的是区间\(\min\)和区间\(\max\)\(\max - \min = (r - l)k\)才有可能是等差数列。
第二个想到的是区间和,用等差数列求和公式判断一下。
但是感觉这样太容易被卡了。在max,min不变的情况下,随意对一对数+1,-1,就卡掉了。
然后想了一下,再跑个区间平方和。但是等差数列平方和怎么做?
\(L = r - l\)\(a_1\)为数列首项(也就是min)。

\[\begin{aligned} \sum_{i = l} ^ r a_i^2 &= \sum_{i = 0} ^ L (a_1 + ik) ^ 2 \\ &= \sum_{i = 0} ^ L (a_1^2 + 2\cdot a_1 ik + i^2k^2)\\ &= \sum_{i = 0} ^ L a_1^2 + 2\cdot a_1 k \sum_{i = 0} ^ L i + k^2 \sum_{i = 0} ^ L i^2\\ \end{aligned} \]

里面几个东西都很平凡。可以\(\mathcal{O}(1)\)求出。
我以为过不去,结果居然AC了!我去

# include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
const long long inf = 1e18;
int n,m;
long long a[N];
struct node
{
    long long val,val2;
    long long Max,Min;
}T[N << 2];
void pushup(int root)
{
    T[root].val = T[root << 1].val + T[root << 1 | 1].val;
    T[root].val2 = T[root << 1].val2 + T[root << 1 | 1].val2;
    T[root].Max = max(T[root << 1].Max,T[root << 1 | 1].Max);
    T[root].Min = min(T[root << 1].Min,T[root << 1 | 1].Min);
    return; 
}
void build(int root,int l,int r)
{
    if(l == r) 
    {
        T[root].val = a[l],T[root].val2 = a[l] * a[l];
        T[root].Max = T[root].Min = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(root << 1,l,mid),build(root << 1 | 1,mid + 1,r);
    pushup(root);
    return;
}
void update(int root,int l,int r,int x,long long d)
{
    if(l == x && r == x)
    {
        T[root].val = d,T[root].val2 = d * d;
        T[root].Max = T[root].Min = d;
        return;
    }
    int mid = (l + r) >> 1;
    if(l <= x && x <= mid) update(root << 1,l,mid,x,d);
    else update(root << 1 | 1,mid + 1,r,x,d);
    pushup(root);
    return;
}
long long query1(int root,int l,int r,int s,int t)
{
    if(l <= s && t <= r) return T[root].val;
    int mid = (s + t) >> 1;
    long long ans = 0;
    if(l <= mid) ans = ans + query1(root << 1,l,r,s,mid);
    if(r > mid) ans = ans + query1(root << 1 | 1,l,r,mid + 1,t);
    return ans;
}
long long query2(int root,int l,int r,int s,int t)
{
    if(l <= s && t <= r) return T[root].val2;
    int mid = (s + t) >> 1;
    long long ans = 0;
    if(l <= mid) ans = ans + query2(root << 1,l,r,s,mid);
    if(r > mid) ans = ans + query2(root << 1 | 1,l,r,mid + 1,t);
    return ans;
}

long long query_max(int root,int l,int r,int s,int t)
{
    if(l <= s && t <= r) return T[root].Max;
    long long ans = -inf;
    int mid = (s + t) >> 1;
    if(l <= mid) ans = max(ans,query_max(root << 1,l,r,s,mid));
    if(r > mid) ans = max(ans,query_max(root << 1 | 1,l,r,mid + 1,t));
    return ans;
}

long long query_min(int root,int l,int r,int s,int t)
{
    if(l <= s && t <= r) return T[root].Min;
    long long ans = inf;
    int mid = (s + t) >> 1;
    if(l <= mid) ans = min(ans,query_min(root << 1,l,r,s,mid));
    if(r > mid) ans = min(ans,query_min(root << 1 | 1,l,r,mid + 1,t));
    return ans;
}

bool check(int l,int r,int k)
{
    long long Min = query_min(1,l,r,1,n),Max = query_max(1,l,r,1,n);
    if(Max - Min != (long long)(r - l) * k * 1ll) return 0;
    long long sum1 = query1(1,l,r,1,n);
    long long sum = (Max + Min) * (long long)(r - l + 1) / 2;
    if(sum1 != sum) return 0;
    sum1 = query2(1,l,r,1,n);
    long long L = (long long)(r - l);
    sum = (L + 1) * Min * Min + 2 * Min * (long long)(k) * ((1ll + L) * L / 2) + (long long) k * (long long) k * (L * (L + 1ll) * (2 * L + 1ll) / (6 * 1ll));
    if(sum != sum1) return 0;
    return 1;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
    build(1,1,n);
    int lstans = 0;
    while(m--)
    {
        int opt; scanf("%d",&opt);
        if(opt == 1)
        {
            int x; long long y; scanf("%d%lld",&x,&y);
            x = x xor lstans,y = y xor lstans;
            update(1,1,n,x,y);
        }
        else
        {
            int l,r,k; scanf("%d%d%d",&l,&r,&k);
            l = l xor lstans,r = r xor lstans,k = k xor lstans;
            bool flag = check(l,r,k);
            if(flag == 1) ++lstans;
            printf("%s\n",flag ? "Yes" : "No");
        }
    }
    return 0;
}

弱化版

posted @ 2021-08-26 15:49  luyiming123  阅读(61)  评论(0编辑  收藏  举报