JSOI 2009 等差數列

2021-08-16 15:37:22 字數 1696 閱讀 1227

給出一串串行

有兩個操作

a s t a b 表示 s t區間內每個數 vi 變成 vi+(i-s)*b+a

b s t 表示 查詢 s t 區間內的數最少可以劃分為幾段等差數列

線段樹玩出花系列~

首先,對於等差數列

我們其實並不需要真實的值

而是前後兩個元素的差值

一段 等差數列 差分之後 值一定是相等的

那麼我們就把序列差分 val[i]=val[i+1]-val[i]

對 差分值建立線段樹

對於操作 1

差分之後等價於

在 s 的位置 +a

而在 t -((a+b*(t-s))

在 s - t-1的位置加上 b

如何統計答案呢

對於每個線段樹區間維護 l,r s[0],s[1],s[2],s[3]

l,r 分別表示區間右端和左端的值

s[0] 左右端點都不選的劃分數,s[1] 選上左端點的劃分數,s[2] 選上右端點的劃分數,s[3] 左右都選的劃分數

以s[0]為例 s[0]=min(lc->s[2]+rc->s[1]-(lc->r==rc->l), lc->s[0]+rc->s[1], lc->s[2]+rc->s[0])

其他依次類推

注意特判和細節!

luogu 4242

bzoj 1558

#include 

#include

#define il inline

#define lson (o<<1)

#define rson (o<<1)|1

il int

read()

while(ch>='0'&&ch<='9')

return

x*w;

}const int maxm=110005;

il int min(int a,int b,int c)

struct node

};struct treest[maxm<<2];

int val[maxm],n,q;

namespace seg

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

int mid=(l+r)>>1;

build(lson,l,mid),build(rson,mid+1,r);

st[o].add=0;

st[o].t=st[(o<<1)].t+st[(o<<1)|1].t;

}il void col(int o,int adx)

il void pushdown(int o)

}void change(int o,int l,int r,int ql,int qr,int num)

pushdown(o);

int mid=(l+r)>>1;

if (ql<=mid) change(lson,l,mid,ql,qr,num);

if (qr>mid) change(rson,mid+1,r,ql,qr,num);

st[o].t=st[(o<<1)].t+st[(o<<1)|1].t;

}node ask(int o,int l,int r,int ql,int qr)

}int main()

else

}return

0;}

BZOJ1558 JSOI2009 等差數列

傳送門等差數列的題麼,先差分一下,然後就變成了乙個數列上,求 l,r 區間內連續相同的段數了。很相似的是 sdoi2011 染色這道題,但是由於我們這個線段樹存的是差分後的陣列,所以需要考慮乙個數是否作為乙個分段的頭和尾造成的影響。這個也是可以使用線段樹快速維護的。include using nam...

bzoj 1558 JSOI2009 等差數列

把原陣列變為差分陣列,然後剩下的就十分顯然了 區間查詢用線段樹維護 修改操作就是區間加法和兩個單點修改 乙個等差數列實際上就是 開頭乙個數字 數值相等的一段 唯一的難點在於討論這個開頭的數字的去向 所以我們可以先不把左右兩端點列入考慮物件,然後在合併時再討論去向,綜上需要維護的東西有 1.區間的左右...

45 等差數列

45 等差數列 問題描述 乙個等差數列是乙個能表示成a,a b,a 2b,a nb n 0,1,2,3,在這個問題中a是乙個非負的整數,b是正整數。寫乙個程式來找出在雙平方數集合s中長度為n的等差數列。雙平方數集合是所有能表示成p2 q2的數的集合。輸入說明 第一行 n 3 n 25 要找的等差數列...