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

来源:互联网 发布:java包名命名规范 编辑:程序博客网 时间:2024/06/01 07:45

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

分类:Data Structure

1. 题目链接

[BZOJ4373算术天才⑨与等差数列]

2. 题意描述

算术天才⑨非常喜欢和等差数列玩耍。
有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。
他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
当然,他还会不断修改其中的某一项。
为了不被他鄙视,你必须要快速并正确地回答完所有问题。
注意:只有一个数的数列也是等差数列。
输入格式:
第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
第二行包含n个整数,依次表示序列中的每个数ai。
接下来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的个数来进行解密。

3. 解题思路

现在假设查询的区间为[l,r],(w=rl+1,a0=minv,aw=maxv),根据等差数列的性质,可得:

  • a0+(w1)k==aw
  • a0+a1++aw=(a0+aw)w2=sum1
  • a20+a21++a2w=w1i=0[a0+ik]2=[wa20]+[k2w1i=0(n1)2]+[2a0kw1i=0(i)]=sum2

用线段树维护区间最小值minv,区间最大值maxv,区间和sum1,区间平方和sum2。
另外,求sum2的过程中还要注意溢出。

4. 实现代码

#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef long double LB;typedef pair<int, int> PII;typedef pair<LL, LL> PLL;typedef vector<int> VI;const int INF = 0x3f3f3f3f;const LL INFL = 0x3f3f3f3f3f3f3f3fLL;#define lson    l, mid, (rt << 1)#define rson    mid + 1, r, (rt << 1 | 1)#define debug(x) cout << "[" << x << "]" << endlconst int MAXN = 300000 + 5;int n, m;LL a[MAXN];struct Node {    LL minv, maxv, sum1, sum2;    Node() {}    Node(LL minv, LL maxv, LL sum1, LL sum2) : minv(minv), maxv(maxv), sum1(sum1), sum2(sum2) {}} nd[MAXN << 2];inline void pushUp(Node& rt, const Node& lch, const Node& rch) {    rt.minv = min(lch.minv, rch.minv);    rt.maxv = max(lch.maxv, rch.maxv);    rt.sum1 = lch.sum1 + rch.sum1;    rt.sum2 = lch.sum2 + rch.sum2;}void build(int l, int r, int rt) {    if (l == r) {        scanf("%lld", &a[l]);        nd[rt].minv = nd[rt].maxv = a[l];        nd[rt].sum1 = a[l];        nd[rt].sum2 = a[l] * a[l];        return;    }    int mid = (l + r) >> 1;    build(lson);    build(rson);    pushUp(nd[rt], nd[rt << 1], nd[rt << 1 | 1]);}void update(const int& p, const LL& x, int l, int r, int rt) {    if (l == r) {        a[l] = x;        nd[rt].minv = nd[rt].maxv = a[l];        nd[rt].sum1 = a[l];        nd[rt].sum2 = a[l] * a[l];        return;    }    int mid = (l + r) >> 1;    if (p <= mid) update(p, x, lson);    else update(p, x, rson);    pushUp(nd[rt], nd[rt << 1], nd[rt << 1 | 1]);}Node query(const int& L, const int& R, int l, int r, int rt) {    if (L <= l && r <= R) {        return nd[rt];    }    int mid = (l + r) >> 1;    Node lop(-1, -1, 0, 0), rop(-1, -1, 0, 0);    if (L <= mid) lop = query(L, R, lson);    if (R > mid) rop = query(L, R, rson);    if (lop.maxv == -1) return rop;    if (rop.maxv == -1) return lop;    return Node(min(lop.minv, rop.minv), max(lop.maxv, rop.maxv), lop.sum1 + rop.sum1, lop.sum2 + rop.sum2);}inline bool check(LL l, LL r, LL k, const Node& e) {    LL w = (r - l + 1);    if (e.minv + (w - 1) * k != e.maxv) return false;    if ((e.minv + e.maxv) * w != e.sum1 * 2) return false;    LL a = w * e.minv * e.minv * 6LL;    LL b = k * k * (w - 1) * w * ((w - 1) << 1 | 1);    LL c = e.minv * k * (w - 1) * w * 6LL;    // printf("[%lld %lld %lld]\n", a, b, c);    if (e.sum2 * 6LL != a + b + c) return false;    return true;}int main() {#ifdef ___LOCAL_WONZY___    freopen("input.txt", "r", stdin);#endif // ___LOCAL_WONZY___    LL op, x, y, l, r, k, cnt = 0;    scanf("%d %d", &n, &m);    a[0] = 0; build(1, n, 1);    while (m --) {        scanf("%lld", &op);        if (op == 1) {            scanf("%lld %lld", &x, &y);            x ^= cnt, y ^= cnt;            assert(x >= 1 && x <= n);            update(x, y, 1, n, 1);        } else {            scanf("%lld %lld %lld", &l, &r, &k);            l ^= cnt, r ^= cnt, k ^= cnt;            assert(l <= r && l >= 1 && l <= n && r >= 1 && r <= n);            if (l == r) {                ++ cnt;                puts("Yes");                continue;            }            Node e = query(l, r, 1, n, 1);            if (k == 0) {                if (e.minv == e.maxv) puts("Yes"), ++ cnt;                else puts("No");                continue;            }            // printf("[%lld %lld %lld %lld]", e.minv, e.maxv, e.sum1, e.sum2);            if (check(l, r, k, e)) puts("Yes"), ++cnt;            else puts("No");        }    }#ifdef ___LOCAL_WONZY___    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // ___LOCAL_WONZY___    return 0;}
0 0
原创粉丝点击