返回顶部

2020牛客寒假算法基础集训营2【J】-求函数(线段树维护矩阵)

题目链接:https://ac.nowcoder.com/acm/contest/3003/J

根据条件构造下列矩阵

 

根据题意不难想到用线段树维护。

注意矩阵乘法的顺序,不遵循交换律,合并区间时右子树在前。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mod=1e9+7,maxn=2e5+10;
 5 inline int lx(signed x){return x<<1;}
 6 inline int rx(signed x){return x<<1|1;}
 7 int kk[maxn],bb[maxn];
 8 struct mat{
 9     ll a11,a12,a21,a22;
10     mat(){}
11     mat(ll a,ll b,ll c,ll d){a11=a,a12=b,a21=c,a22=d;}
12     friend mat operator *(mat a,mat b){
13         return mat(
14                 (a.a11*b.a11+a.a12*b.a21)%mod,
15                 (a.a11*b.a12+a.a12*b.a22)%mod,
16                 (a.a21*b.a11+a.a22*b.a21)%mod,
17                 (a.a21*b.a21+a.a22*b.a22)%mod
18                 );
19     }
20 };
21 struct Node{
22     int l,r;
23     mat val;
24 }tree[maxn<<2];
25 inline void pushup(int root){tree[root].val=tree[rx(root)].val*tree[lx(root)].val;}
26 void build(int root,int l,int r){
27     tree[root].l=l,tree[root].r=r;
28     if(l==r){
29         tree[root].val=mat(kk[l],bb[l],0,1);
30         return;
31     }
32     int mid=(l+r)>>1;
33     build(lx(root),l,mid);
34     build(rx(root),mid+1,r);
35     pushup(root);
36 }
37 void update(int pos,mat ma,int root){
38     if(tree[root].l==tree[root].r){
39         tree[root].val=ma;
40         return;
41     }
42     int mid=(tree[root].l+tree[root].r)>>1;
43     if(pos<=mid)
44         update(pos,ma,lx(root));
45     else
46         update(pos,ma,rx(root));
47     pushup(root);
48 }
49 mat query(int l,int r,int root){
50     assert(r>=l);
51     int mid=(tree[root].l+tree[root].r)>>1;
52     if(tree[root].l==l&&tree[root].r==r)return tree[root].val;
53     if(mid>=r)return query(l,r,lx(root));
54     else if (mid<l)return query(l,r,rx(root));
55     else return query(mid+1,r,rx(root))*query(l,mid,lx(root));
56 }
57 int main(){
58     int n,m;
59     scanf("%d %d",&n,&m);
60     for(int i=1;i<=n;i++)
61         scanf("%d",&kk[i]);
62     for(int i=1;i<=n;i++)
63         scanf("%d",&bb[i]);
64     build(1,1,n);
65     while(m--){
66         int op;
67         cin>>op;
68         if(op==1){
69             int i,k,b;
70             scanf("%d%d%d",&i,&k,&b);
71             update(i,mat(k,b,0,1),1);
72         }else{
73             int l,r;
74             scanf("%d %d",&l,&r);
75             mat res=query(l,r,1);
76             printf("%lld\n",(res.a11+res.a12)%mod);
77         }
78     }
79     return 0;
80 }

----------------------------------------------分割线---------------------------------------------------------------------------------------

另附官方题解

 

 标程很短就不贴了,以我的脑子现场一时半会儿应该是推不出来的QAQ

 

posted @ 2020-02-06 20:30  Charles1999  阅读(155)  评论(0编辑  收藏  举报