日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

牛客 - 求函数(线段树+区间合并/线段树+矩阵维护)

發布時間:2024/4/11 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 牛客 - 求函数(线段树+区间合并/线段树+矩阵维护) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:現在有 n 個函數,每個函數都是諸如 f( x ) = k * x + b 的形式,只是每個函數的 k 和 b 都是相互獨立的,現在給出兩個操作:

  • 1 pos k b:將第 pos 個函數的參數變為 k 和 b?
  • 2 l r:求出?
  • 題目分析:算半個數學問題吧,第一步是需要將題目中的公式轉換一下,因為直接遞歸模擬肯定是要超時的,因為題目也給到了提示,就是用 l 和 r 表示下標,很容易聯想到區間問題,這樣操作一就是單點更新,操作二就是區間查詢了,也就是需要借助線段樹來實現,想到了這一步的話,還是化簡一下公式吧,其實自己在紙上算兩下應該就能算出來了,比較簡單:

    注意上面公式中的 j == r + 1時的 k_j == 1

    然后就是考慮加法兩邊的部分分別用兩個線段樹來維護,方便起見我們分別表示為 tree1 和 tree2 ,現在需要考慮如何合并:

    因為前半部分是累乘,所以直接累乘就好了:

    tree1[ k ] = tree1[ k << 1 ] * tree1[ k << 1 | 1 ]

    后半部分的話稍微麻煩一點,在紙上畫一下會發現左兒子需要再乘上右兒子 tree1 的答案,也就是:

    tree2[ k ] = tree2[ k << 1 ] * tree1[ k << 1 | 1 ]+ tree2[ k << 1 | 1 ]

    剩下的實現就好了,兩棵樹維護起來比較麻煩,不過還是有技巧可尋的


    2020.2.7更新:

    水群的時候發現還可以用矩陣來描述轉移,因為

    顯然可以發現對于矩陣存在轉移關系,用線段樹維護就好了,實現起來比區間合并簡單了好多

    代碼:

    線段樹+區間合并:

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100;const int mod=1e9+7;int K[N],B[N];struct Node {int l,r;LL sum; }tree1[N<<2],tree2[N<<2];void build(int k,int l,int r) {tree1[k].l=tree2[k].l=l;tree1[k].r=tree2[k].r=r;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void update(int k,int pos,int K,int B) {if(tree1[k].l==tree1[k].r){tree1[k].sum=K;tree2[k].sum=B;return;}int mid=tree1[k].l+tree1[k].r>>1;if(mid>=pos)update(k<<1,pos,K,B);elseupdate(k<<1|1,pos,K,B);tree1[k].sum=tree1[k<<1].sum*tree1[k<<1|1].sum%mod;tree2[k].sum=(tree2[k<<1].sum*tree1[k<<1|1].sum%mod+tree2[k<<1|1].sum)%mod; }pair<LL,LL> merge(pair<LL,LL> a,pair<LL,LL> b)//左半段和右半段合并 {return make_pair(a.first*b.first%mod,(a.second*b.first%mod+b.second)%mod); }pair<LL,LL> query(int k,int l,int r) {if(tree1[k].r<l||tree1[k].l>r)return make_pair(1,0);if(tree1[k].l>=l&&tree1[k].r<=r)return make_pair(tree1[k].sum,tree2[k].sum);return merge(query(k<<1,l,r),query(k<<1|1,l,r)); }int main() { //#ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); //#endif // ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);build(1,1,n);for(int i=1;i<=n;i++)scanf("%d",K+i);for(int i=1;i<=n;i++)scanf("%d",B+i);for(int i=1;i<=n;i++)update(1,i,K[i],B[i]);while(m--){int op;scanf("%d",&op);if(op==1){int pos,k,b;scanf("%d%d%d",&pos,&k,&b);update(1,pos,k,b);}else{int l,r;scanf("%d%d",&l,&r);pair<LL,LL>ans=query(1,l,r);printf("%lld\n",(ans.first+ans.second)%mod);}}return 0; }

    線段樹+矩陣:

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100;const int mod=1e9+7;struct Ma {LL a[2][2];Ma(){memset(a,0,sizeof(a));}static Ma ONE()//返回單位矩陣 {Ma ans;for(int i=0;i<2;i++)ans.a[i][i]=1;return ans;}friend Ma operator * (const Ma& a,const Ma& b){Ma ans;for(int i=0;i<2;i++)for(int j=0;j<2;j++){ans.a[i][j]=0;for(int k=0;k<2;k++)ans.a[i][j]+=a.a[i][k]*b.a[k][j];ans.a[i][j]%=mod;}return ans;} };struct Node {int l,r;Ma node; }tree[N<<2];void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].node.a[0][1]=0;tree[k].node.a[1][1]=1;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void update(int k,int pos,int K,int B) {if(tree[k].l==tree[k].r){tree[k].node.a[0][0]=K;tree[k].node.a[1][0]=B;return;}int mid=tree[k].l+tree[k].r>>1;if(mid>=pos)update(k<<1,pos,K,B);elseupdate(k<<1|1,pos,K,B);tree[k].node=tree[k<<1].node*tree[k<<1|1].node; }Ma query(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l)return Ma::ONE();if(tree[k].l>=l&&tree[k].r<=r)return tree[k].node;return query(k<<1,l,r)*query(k<<1|1,l,r); }int a[N];int main() { //#ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); //#endif // ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m); build(1,1,n);for(int i=1;i<=n;i++)scanf("%d",a+i);for(int i=1;i<=n;i++){int x;scanf("%d",&x);update(1,i,a[i],x);}while(m--){int op;scanf("%d",&op);if(op==1){int pos,k,b;scanf("%d%d%d",&pos,&k,&b);update(1,pos,k,b);}else{int l,r;scanf("%d%d",&l,&r);Ma ans=query(1,l,r);printf("%lld\n",(ans.a[0][0]+ans.a[1][0])%mod);}} return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的牛客 - 求函数(线段树+区间合并/线段树+矩阵维护)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。