1. 程式人生 > >Codeforces 718C. Sasha and Array(線段樹)

Codeforces 718C. Sasha and Array(線段樹)

傳送門

解題思路:

這道題給了我們一個嶄新的角度來看線段樹。

我們常常使用的線段樹是維護區間的函式的。

這裡呢,提示我們線段樹其實還可以維護遞推。

美好的矩陣遞推性質支援了這一功能。

或者說,對於遞推項求和,可以使用線段樹維護矩陣。

區間向前遞推可以用懶惰標記記錄遞推矩陣。

區間的查詢可以是子節點矩陣和。

這其實也是滿足分配率的。

最後pushup,pushdown搞一搞就好了。

程式碼(閒來無事卡常碼風突變)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4
#define lll spc<<1 5 #define rrr spc<<1|1 6 typedef unsigned long long lnt; 7 typedef unsigned int ixt; 8 const lnt mod=(lnt)(1e9+7); 9 struct squ{ 10 lnt s[2][2]; 11 inline void res(void) 12 { 13 memset(s,0,sizeof(s)); 14 return ; 15
} 16 inline void O1(void) 17 { 18 for(register int i=0;i<2;i++) 19 s[i][i]=1; 20 return ; 21 } 22 inline squ friend operator + (const squ &a,const squ &b) 23 { 24 squ ans; 25 for(register int i=0;i<2;i++)
26 { 27 for(register int j=0;j<2;j++) 28 { 29 ans.s[i][j]=(a.s[i][j]+b.s[i][j])%mod; 30 } 31 } 32 return ans; 33 } 34 inline squ friend operator * (const squ &a,const squ &b) 35 { 36 squ ans; 37 for(register int i=0;i<2;i++) 38 { 39 for(register int j=0;j<2;j++) 40 { 41 ans.s[i][j]=0; 42 for(register int k=0;k<2;k++) 43 { 44 ans.s[i][j]=(ans.s[i][j]+a.s[i][k]*b.s[k][j])%mod; 45 } 46 } 47 } 48 return ans; 49 } 50 inline squ friend operator ^ (squ a,lnt b) 51 { 52 squ ans=a; 53 b--; 54 while(b) 55 { 56 if(b&1) 57 ans=ans*a; 58 a=a*a; 59 b=b/2; 60 } 61 return ans; 62 } 63 }sta,pro; 64 struct trnt{ 65 squ sum; 66 squ lzt; 67 bool op; 68 }tr[1000000]; 69 ixt n,m; 70 ixt a[1000000]; 71 inline void read(ixt &ans) 72 { 73 ans=0; 74 char ch=getchar(); 75 while(ch<'0'||ch>'9') 76 ch=getchar(); 77 while(ch>='0'&&ch<='9') 78 ans=ans*10+ch-'0',ch=getchar(); 79 return ; 80 } 81 inline squ Fib(const lnt &x) 82 { 83 squ tmp=pro^x; 84 return tmp*sta; 85 } 86 inline void pushup(const int &spc) 87 { 88 tr[spc].sum=tr[lll].sum+tr[rrr].sum; 89 return ; 90 } 91 inline void add(const int &spc,const squ &v) 92 { 93 tr[spc].op=true; 94 tr[spc].lzt=v*tr[spc].lzt; 95 tr[spc].sum=v*tr[spc].sum; 96 return ; 97 } 98 inline void pushdown(const int &spc) 99 { 100 if(tr[spc].op) 101 { 102 add(lll,tr[spc].lzt); 103 add(rrr,tr[spc].lzt); 104 tr[spc].lzt.res(); 105 tr[spc].lzt.O1(); 106 tr[spc].op=0; 107 } 108 return ; 109 } 110 inline void build(const int &l,const int &r,const int &spc) 111 { 112 tr[spc].lzt.res(); 113 tr[spc].lzt.O1(); 114 if(l==r) 115 { 116 tr[spc].sum=Fib(a[l]); 117 return ; 118 } 119 int mid=(l+r)>>1; 120 build(l,mid,lll); 121 build(mid+1,r,rrr); 122 pushup(spc); 123 return ; 124 } 125 inline void update(const int &l,const int &r,const int &ll,const int &rr,const int &spc,const squ &v) 126 { 127 if(ll>r||l>rr) 128 return ; 129 if(ll<=l&&r<=rr) 130 { 131 add(spc,v); 132 return ; 133 } 134 int mid=(l+r)>>1; 135 pushdown(spc); 136 update(l,mid,ll,rr,lll,v); 137 update(mid+1,r,ll,rr,rrr,v); 138 pushup(spc); 139 return ; 140 } 141 inline squ query(const int &l,const int &r,const int &ll,const int &rr,const int &spc) 142 { 143 squ ans; 144 ans.res(); 145 if(l>rr||ll>r) 146 return ans; 147 if(ll<=l&&r<=rr) 148 return tr[spc].sum; 149 int mid=(l+r)>>1; 150 pushdown(spc); 151 return query(l,mid,ll,rr,lll)+query(mid+1,r,ll,rr,rrr); 152 } 153 int main() 154 { 155 sta.s[0][0]=0; 156 sta.s[1][0]=1; 157 pro.s[0][0]=1; 158 pro.s[0][1]=1; 159 pro.s[1][0]=1; 160 read(n); 161 read(m); 162 for(register int i=1;i<=n;i++) 163 scanf("%d",&a[i]); 164 build(1,n,1); 165 while(m--) 166 { 167 ixt opt; 168 read(opt); 169 if(opt==1) 170 { 171 ixt l,r,x; 172 read(l); 173 read(r); 174 read(x); 175 if(!x) 176 continue; 177 squ tmp=pro^x; 178 update(1,n,l,r,1,tmp); 179 }else{ 180 ixt l,r; 181 read(l); 182 read(r); 183 printf("%I64u\n",(query(1,n,l,r,1).s[0][0]%mod+mod)%mod); 184 } 185 } 186 return 0; 187 }