一个显然的结论是c[j]对f[x][y]的贡献系数为从(1,j)走到(x,y)的方案数。
60pts
发现x很小,考虑用一个大小为20n线段树来维护
区间[l,r]表示l到r中的所有ci对r的贡献值
合并的时候f[l,r,i]=f[mid+1,r,i]+∑f[l,mid,j]c(i-j+r-(mid+1),i-j);
这个式子的含义:
首先f[mid+1,r,i]的含义很明显
左边考虑去枚举所有最后对r产生贡献的方案在走到mid的时候所处的行
这些显然互斥且可以表示全集
然后每一种走到(j,mid)方案,有c(i-j+r-(mid+1)种方案走到(i,r)//这里第一步强制只能往右走
用线段树维护的复杂度为O(nlogn2020)
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define K 25
#define N 221000
#define L 220000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline ll read()
{
char ch=0;
ll x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
const ll mo=1000000007;
ll x,y,c[N][K];
ll exgcd(ll a,ll b)
{
if(!b)
{
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b);
ll t=x;
x=y;
y=t-(a/b)*y;
return d;
}
ll inv(ll o)
{
exgcd(((o%mo)+mo)%mo,mo);
return ((x%mo)+mo)%mo;
}
ll n,m,v[N],w[N];
struct node
{
ll f[K];
};
struct Segment_Tree
{
#define lson o<<1
#define rson o<<1|1
#define mid ((l+r)>>1)
ll dp[N*4][K];
inline void pushup(ll o,ll l,ll r)
{
for(ll i=1;i<=20;i++)
{
dp[o][i]=dp[rson][i];
for(ll j=1;j<=i;j++)
dp[o][i]=(dp[o][i]+((dp[lson][j]*c[i-j+r-(mid+1)][i-j])%mo))%mo;
}
}
void build(ll o,ll l,ll r)
{
if(l==r)
{
for(ll i=1;i<=20;i++)dp[o][i]=w[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
pushup(o,l,r);
}
void optset(ll o,ll l,ll r,ll q,ll num)
{
if(l==r)
{
for(ll i=1;i<=20;i++)dp[o][i]=num;
return;
}
if(q<=mid)optset(lson,l,mid,q,num);
if(q>mid)optset(rson,mid+1,r,q,num);
pushup(o,l,r);
}
node query(ll o,ll l,ll r,ll ql,ll qr)
{
if(ql<=l&&r<=qr)
{
node ans;
for(ll i=1;i<=20;i++)ans.f[i]=dp[o][i];
return ans;
}
bool flag1=false,flag2=false;
if(ql<=mid)flag1=true;
if(qr>mid)flag2=true;
if(flag1&&flag2)
{
node a=query(lson,l,mid,ql,qr);
node b=query(rson,mid+1,r,ql,qr);
node ans;
for(ll i=1;i<=20;i++)
{
ans.f[i]=b.f[i];
for(ll j=1;j<=i;j++)
ans.f[i]=(ans.f[i]+((a.f[j]*c[i-j+qr-(mid+1)][i-j])%mo))%mo;
}
return ans;
}
else
{
if(flag1)return query(lson,l,mid,ql,qr);
if(flag2)return query(rson,mid+1,r,ql,qr);
}
}
}T;
int main()
{
ll i,p,k,x,y,flag;
n=read();m=read();
for(i=1;i<=L;i++)v[i]=inv(i);
for(k=0;k<=20;k++)
{
c[k][k]=1;
for(i=k;i<=L;i++)
c[i+1][k]=(c[i][k]*(((i+1)*v[i-k+1])%mo))%mo;
}
for(i=1;i<=n;i++)w[i]=read();
T.build(1,1,n);
for(p=1;p<=m;p++)
{
flag=read();x=read();y=read();
if(flag==1)
{
T.optset(1,1,n,x,y);
w[x]=y;
}
else
{
if(x==0)
{
printf("%lld\n",w[y]);
continue;
}
ll ans=0;
node o=T.query(1,1,n,1,y);
printf("%lld\n",o.f[x]);
}
}
return 0;
}