5-14 数据结构啊poi A.暑假作业

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=78124#problem/A

//想看题目的@willinglive

用线段树维护这种东西还是第一次写。。

我们先考虑合并操作。维护F0开始乘的区间和和F1开始乘的区间和。只需要把右边那段乘上一个矩阵再加上左边那段就可以了

单点修改直接做就可以了

区间加呢?我们观察到每次区间加x就等于把区间加上x*(F0+……+F(r-l))。那么维护个懒标记就可以了

一开始数组开小了不然就1A了

#include<cstdio>
#include<algorithm>
using namespace std;
struct tree
{
     int l,r;
     long long s[2];
     long long tag;
}tr[1600001];
int a[200001];
long long mod=1000000000;
long long mat[200006][3][3];
long long f[200006];
long long sx[200006];
inline void power(int n)
{
     mat[0][1][1]=1;
     mat[0][1][2]=0;
     mat[0][2][1]=0;
     mat[0][2][2]=1;
     mat[1][1][1]=0;
     mat[1][1][2]=1;
     mat[1][2][1]=1;
     mat[1][2][2]=1;
     int i,j,k;
     for(k=2;k<=n+5;k++)
          for(i=1;i<=2;i++)
               for(j=1;j<=2;j++)
                    mat[k][i][j]=(mat[k-1][i][1]*mat[1][1][j]%mod+mat[k-1][i][2]*mat[1][2][j]%mod)%mod;
     f[1]=1;
     f[2]=1;
     sx[1]=1;
     sx[2]=2;
     for(k=3;k<=n+5;k++)
     {
          f[k]=(f[k-1]+f[k-2])%mod;
          sx[k]=(sx[k-1]+f[k])%mod;
     }
}
inline void up(int p)
{
	 int len=tr[p*2].r-tr[p*2].l+1;
     tr[p].s[0]=((tr[p*2].s[0]+mat[len][1][1]*tr[p*2+1].s[0]%mod)%mod+mat[len][2][1]*tr[p*2+1].s[1]%mod)%mod;
     tr[p].s[1]=((tr[p*2].s[1]+mat[len][1][2]*tr[p*2+1].s[0]%mod)%mod+mat[len][2][2]*tr[p*2+1].s[1]%mod)%mod;
}
inline void down(int p)
{
	 if(tr[p].tag==0)
	      return ;
     int len=tr[p].r-tr[p].l+1;
     int len1=len-len/2,len2=len/2;
     long long x=tr[p].tag;
     tr[p].tag=0;
     tr[p*2].s[0]=(tr[p*2].s[0]+x*sx[len1]%mod)%mod;
     tr[p*2].s[1]=(tr[p*2].s[1]+x*(sx[len1+1]-1)%mod)%mod;
     tr[p*2].tag=(tr[p*2].tag+x)%mod;
     tr[p*2+1].s[0]=(tr[p*2+1].s[0]+x*sx[len2]%mod)%mod;
     tr[p*2+1].s[1]=(tr[p*2+1].s[1]+x*(sx[len2+1]-1)%mod)%mod;
     tr[p*2+1].tag=(tr[p*2+1].tag+x)%mod;
}
inline void build(int p,int l,int r)
{
     tr[p].l=l;
     tr[p].r=r;
     if(l!=r)
     {
          int mid=(l+r)/2;
          build(p*2,l,mid);
          build(p*2+1,mid+1,r);
          up(p);
     }
     else
     {
          tr[p].s[0]=a[l];
          tr[p].s[1]=a[l];
     }
}
inline void change(int p,int l,int r,int x)
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          tr[p].s[0]=x;
          tr[p].s[1]=x;
     }
     else
     {
     	  down(p);
          int mid=(tr[p].l+tr[p].r)/2;
          if(l<=mid)
               change(p*2,l,r,x);
          if(r>mid)
               change(p*2+1,l,r,x);
          up(p);
     }
}
inline void cover(int p,int l,int r,int x)
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
     	  int len=tr[p].r-tr[p].l+1;
          tr[p].s[0]=(tr[p].s[0]+x*sx[len]%mod)%mod;
          tr[p].s[1]=(tr[p].s[1]+x*(sx[len+1]-1)%mod)%mod;
          tr[p].tag=(tr[p].tag+x)%mod;
     }
     else
     {
     	  down(p);
          int mid=(tr[p].l+tr[p].r)/2;
          if(l<=mid)
               cover(p*2,l,r,x);
          if(r>mid)
               cover(p*2+1,l,r,x);
          up(p);
     }
}
tree nw;
inline tree ask(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p];
     else
     {
     	  down(p);
          int mid=(tr[p].l+tr[p].r)/2;
          tree ans1=nw,ans2=nw,ans=nw;
          bool flag1=false,flag2=false;
          if(l<=mid)
          {
               flag1=true;
               ans1=ask(p*2,l,r);
          }
          if(r>mid)
          {
               flag2=true;
               ans2=ask(p*2+1,l,r);
          }
          if(flag1)
          {
               if(flag2)
               {
                    ans.l=ans1.l;
                    ans.r=ans2.r;
                    int len=ans1.r-ans1.l+1;
                    ans.s[0]=((ans1.s[0]+mat[len][1][1]*ans2.s[0]%mod)%mod+mat[len][2][1]*ans2.s[1]%mod)%mod;
                    ans.s[1]=((ans1.s[1]+mat[len][1][2]*ans2.s[0]%mod)%mod+mat[len][2][2]*ans2.s[1]%mod)%mod;
               }
               else
                    ans=ans1;
          }
          else
               ans=ans2;
          return ans;
     }
}
int main()
{
     int n,m;
     scanf("%d%d",&n,&m);
     int i;
     for(i=1;i<=n;i++)
          scanf("%d",&a[i]);
     power(n);
     build(1,1,n);
     int x,s,t;
     for(i=1;i<=m;i++)
     {
          scanf("%d",&x);
          if(x==1)
          {
          	   scanf("%d%d",&s,&t);
               change(1,s,s,t);
          }
          else if(x==2)
          {
               scanf("%d%d",&s,&t);
               printf("%lld\n",ask(1,s,t).s[0]);
          }
          else
          {
               scanf("%d%d%d",&s,&t,&x);
               cover(1,s,t,x);
          }
     }
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值