https://www.nowcoder.com/acm/contest/147/H
分块法真的奇妙 更新操作够2000次就n*k的统一更新一次 期间所有更新存起来 有查询了先把之前已经更新好的数组里的内容取出来 然后把存起来还没更新的操作算一遍即可
正解线段树或树状数组
线段树迷之T
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll M=1000000007;
struct node
{
int x;
ll y;
};
node order[100010];
ll a[50][100010];
ll pre[200010],ni[200010];
int n,q,k,cnt;
ll quickpow(ll a,ll b)//
{
ll res;
res=1;
while(b>0)
{
if(b%2) res=(res*a)%M;
a=(a*a)%M,b/=2;
}
return res;
}
void init()//
{
ll i;
pre[0]=1,ni[0]=1;
for(i=1;i<=200000;i++)
{
pre[i]=(pre[i-1]*i)%M;
ni[i]=quickpow(pre[i],M-2);
}
}
ll getck(int nn,int kk)//
{
if(nn<kk) return 0;
return (pre[nn]*ni[kk]%M)*ni[nn-kk]%M;
}
void force()
{
int i,j;
for(i=1;i<=2000;i++) a[0][order[i].x]=(a[0][order[i].x]+order[i].y)%M;
for(i=1;i<=k;i++)
{
for(j=1;j<=n;j++)
{
a[i][j]=(a[i-1][j]+a[i][j-1])%M;
}
}
}
int main()
{
ll y,ans;
int i,op,x;
init();
while(scanf("%d%d%d",&n,&q,&k)!=EOF)
{
memset(a,0,sizeof(a));
cnt=0;
while(q--)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%lld",&x,&y);
cnt++;
order[cnt].x=x,order[cnt].y=y;
if(cnt==2000)
{
force();
cnt=0;
}
}
else
{
scanf("%d",&x);
ans=a[k][x];
for(i=1;i<=cnt;i++)
{
if(order[i].x>x) continue;
ans=(ans+(getck(k+x-order[i].x-1,k-1)*order[i].y)%M)%M;
//ans=(ans+getck(x-order[i].x+k,x-order[i].x))%M;
}
printf("%lld\n",ans);
}
}
}
return 0;
}