CF719E(線段樹 矩陣快速冪)

2022-01-29 12:46:21 字數 1943 閱讀 6872

題意:給你乙個數列a,a[i]表示斐波那契數列的下標為a[i],求區間對應斐波那契數列數字的和,還要求能夠維護對區間內所有下標加d的操作

分析:線段樹

線段樹的每個節點表示(f[i],f[i-1])這個陣列

因為矩陣的可加性,所以可以進行lazy操作

我最開始的想法是每個節點lazy表示該區間下標加了多少,add表示該區間已經加的下標對應的矩陣乘積,這樣更新lazy是o(1)的,算add是o(logn)的

但是這樣每次pushdown的時候,add下傳總要多個log,會tle

更好的辦法是lazy表示加的下標對應的矩陣乘積,這樣雖然每次更新lazy是o(logn)的,但是pushdown的時候就是直接把(f[i],f[i-1])和lazy[2][2]乘起來了,是o(1)的

**:

1 #include2

const

int maxn=1e5;

3const

long

long mod=1e9+7;4

int ch[maxn*2+50][2];5

long

long sum[maxn*2+50][2],add[maxn*2+50][2][2],a[maxn+50];6

int len=0

,n,m;

7void mer(long

long a[2][2],long

long b[2][2])8

19void fib(long

long num[2][2],long

long

x)20

,};22 num[0][0]=1,num[0][1]=0,num[1][0]=0,num[1][1]=1;23

while

(x)2429}

30void cal(long

long sum[2],long

long s[2][2

])31

36void pushdown(int

k)37

46void update(int

k)47

54int build(int l,int

r)55

69 ch[k][0]=build(l,mid);

70 ch[k][1]=build(mid+1

,r);

71update(k);

72return

k;73

//printf("%d %d %d %d %d\n",l,r,k,ch[k][0],ch[k][1]);74}

75void make(int k,int l,int r,int x,int y,long

long num[2][2

])76

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

pushdown(k);

87if(l<=mid) make(ch[k][0

],l,mid,x,y,num);

88if(r>mid) make(ch[k][1],mid+1

,r,x,y,num);

89update(k);90}

91long

long query(int k,int l,int r,int x,int

y)92

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

;100

pushdown(k);

101return (query(ch[k][0],l,mid,x,y)+query(ch[k][1],mid+1,r,x,y))%mod;

102}

103int

main()

104123

else printf("

%lld\n

",query(1,1

,n,l,r));

124}

125return0;

126 }

view code

514E 矩陣快速冪 DP

一棵樹,每個結點有n個兒子,該第i個兒子到父節點的距離為d i 問離根節點距離不超過x的結點有多少個,結果對1e9 7取模。首先注意到每個di 100資料很小,如果用ti表示所有n中分支中長度為i的個數,那麼就有t 1 100 用dp i 表示到根節點長度為i的點的個數,那麼不難發現狀態轉移方程 d...

CF671E(線段樹 單調棧)

傳送門 神仙題,看題解看了乙個多小時才看懂 首先我們設 pre i 和 suf i 分別表示 1 到 i 需要的額外油量和 i 到 1 需要的額外油量,那麼有 begin pre i pre a w suf i suf a i w end 從 i 向右走到 j 需要的額外油量是 pre j pre ...

做題 cf603E 線段樹分治

首先感謝題解小哥,他在標算外又總結了三種做法。此處僅提及最後一種做法。首先考慮題目中要求的所有結點度數為奇數的限制。對於每乙個聯通塊,因為所有結點總度數是偶數,所以總結點數也必須是偶數的。即所有聯通塊都要是偶數大小。而考慮任意乙個偶數大小的聯通塊,我們任意取它的乙個生成樹,然後進行如下演算法 設 1...