題意:給你乙個數列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 #include2view codeconst
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 }
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...