您的位置:首页 > 其它

bzoj2962 序列操作 线段树

2017-09-16 08:40 411 查看
题意:一段序列,三种操作:

1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。

一开始没看到k<=20,觉得不可做,后来一看,哦这不就水了很多了。。

操作3的话维护f[i]表示当前区间选择i个的答案,那么n^2更新,明显有:

f[i]=f[j]∗f[i−j];(j<i)

取负也很简单,只有奇数的时候才会有影响。

问题就是区间加有些难以处理。

假设加上x,区间长度为len,那么就是类似于(.....+x)(.....+x)(......+x)这样的一个东西。

那么我们枚举x有j个,答案就是∑j=0ixj∗f[i−j]∗Cjlen−i+j

后面那个组合数应该挺好理解,i-j个数字被确定,剩下的len-i+j个中选出j个x。

3000多B让我有点爽。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=50005;
const int mo=19940417;
typedef long long ll;
int n,m;
struct node
{
int l,r,lazy1,lazy2;
ll f[21];;
}t[N*5];
int a
;
int c
[30];
inline void update(int x)
{
fo(i,0,20)
{
t[x].f[i]=0;
fo(j,0,i)t[x].f[i]=(t[x].f[i]+t[x<<1].f[j]*t[x<<1|1].f[i-j])%mo;
}
}
inline void push1(int x)
{
for(int i=1;i<=20;i+=2)t[x].f[i]*=-1;
}
inline void push2(int x,int l,int r,int v)
{
int len=r-l+1;
fd(i,min(len,20),1)
{
ll tmp=0;int mi=1;
fo(j,0,i)tmp=(tmp+1ll*mi*t[x].f[i-j]%mo*c[len-i+j][j])%mo,mi=1ll*mi*v%mo;
t[x].f[i]=tmp;
}
}
inline void build(int x,int l,int r)
{
t[x].l=l,t[x].r=r;t[x].lazy1=1;
if (l==r)
{
t[x].f[1]=a[l];
t[x].f[0]=1;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
update(x);
}
inline void pushdown(int x,int l,int r)
{
if (l==r)return;
int mid=(l+r)>>1,w=t[x].lazy2;
if (t[x].lazy1==-1)
{
push1(x<<1),push1(x<<1|1);
t[x<<1].lazy1*=-1,t[x<<1|1].lazy1*=-1;
t[x<<1].lazy2*=-1,t[x<<1|1].lazy2*=-1;
t[x].lazy1=1;
}
if (w)
{
push2(x<<1,l,mid,w),push2(x<<1|1,mid+1,r,w);
t[x<<1].lazy2=(t[x<<1].lazy2+w)%mo;
t[x<<1|1].lazy2=(t[x<<1|1].lazy2+w)%mo;
t[x].lazy2=0;
}
}
inline void add(int x,int l,int r,int v)
{
if (l>r)return;
pushdown(x,t[x].l,t[x].r);
if (t[x].l==l&&t[x].r==r)
{
push2(x,t[x].l,t[x].r,v);
t[x].lazy2=(t[x].lazy2+v)%mo;
return;
}
int mid=(t[x].l+t[x].r)>>1;
add(x<<1,l,min(r,mid),v);
add(x<<1|1,max(l,mid+1),r,v);
update(x);
}
inline void oppo(int x,int l,int r)
{
if (l>r)return;
pushdown(x,t[x].l,t[x].r);
if (t[x].l==l&&t[x].r==r)
{
push1(x);
t[x].lazy1*=-1;
return;
}
int mid=(t[x].l+t[x].r)>>1;
oppo(x<<1,l,min(r,mid));
oppo(x<<1|1,max(l,mid+1),r);
update(x);
}
inline node query(int x,int l,int r,int v)
{
pushdown(x,t[x].l,t[x].r);
if (t[x].l==l&&t[x].r==r)return t[x];
int mid=(t[x].l+t[x].r)>>1;
if (r<=mid)return query(x<<1,l,r,v);
else if (l>mid)return query(x<<1|1,l,r,v);
else
{
node a=query(x<<1,l,mid,v),
b=query(x<<1|1,mid+1,r,v),ans;
fo(i,0,v)
{
ans.f[i]=0;
fo(j,0,i)
ans.f[i]=(ans.f[i]+a.f[j]*b.f[i-j]%mo)%mo;
}
return ans;
}
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d",&a[i]);
build(1,1,n);
c[0][0]=1;
fo(i,1,n)
{
c[i][0]=1;
fo(j,1,20)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
}
fo(i,1,m)
{
char ch[2];
int l,r,v;
scanf("%s",ch);
if (ch[0]=='I')scanf("%d%d%d",&l,&r,&v),add(1,l,r,v%mo);
else if (ch[0]=='R')scanf("%d%d",&l,&r),oppo(1,l,r);
else
{
scanf("%d%d%d",&l,&r,&v);
node x=query(1,l,r,v);
printf("%lld\n",(x.f[v]+mo)%mo);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: