BZOJ4373算術天才 與等差數列 線段樹

2021-07-30 16:54:57 字數 2979 閱讀 9927

分類:data structure

[bzoj4373算術天才⑨與等差數列]

算術天才⑨非常喜歡和等差數列玩耍。

有一天,他給了你乙個長度為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的個數來進行解密。

現在假設查詢的區間為[l

,r],

令(w=

r−l+

1,a0

=min

v,aw

=max

v),根據等差數列的性質,可得:

用線段樹維護區間最小值minv,區間最大值maxv,區間和sum1,區間平方和sum2。

另外,求sum2的過程中還要注意溢位。

#include 

using

namespace

std;

typedef

long

long ll;

typedef

long

double lb;

typedef pair pii;

typedef pairpll;

typedef

vector

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 << "]" << endl

const

int maxn = 300000 + 5;

int n, m;

ll a[maxn];

struct 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)

void build(int l, int r, int rt)

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)

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)

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)

int main() else

node e = query(l, r, 1, n, 1);

if (k == 0)

// 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;}

bzoj4373 算術天才 與等差數列

bzoj4373 算術天才 與等差數列 給定乙個長為 n 的序列 a i 有 m 次操作 n,m leq3 times10 5,0 leq a i,k leq10 9 線段樹,hash 區間 l,r 所組成的等差數列首項為 min 末項為 max 公差為 k 可以考慮求出 l,r 和這個等差數列的h...

BZOJ1558 等差數列(線段樹)

題目大意 給出長為n n 100000 的序列v,q q 100000 次操作,每次對當前序列的 s,t 加上以a為首項b為公差的等差數列,或詢問當前序列 s,t 最少能劃分成多少段等差數列。題解 神奇的線段樹!等差數列差分之後值是相同的,便於統計最少劃分數,所以我們可以維護差分陣列。這樣修改操作就...

牛牛的等差數列 線段樹

這裡的突破口在於小於等於25且大於等於3的質數連乘在1e8左右,所以,我們可以在操作上,將其看作對1e8去求模,而不是對每個都進行預處理。時間複雜度 include include include include include include include include include inc...