zoukankan      html  css  js  c++  java
  • 序列操作 BZOJ2962 线段树

    分析:

    数据范围表示:c特别的小(c<20)

    我们可以考虑nlogn*c^2的算法。

    线段树维护区间信息:f[i]表示在[l,r]这段区间中选择i个数相乘的和。

    因此,我们可以将区间看成一个点,在PushUp的时候用背包的方式更新父节点。(仔细观察发现这是卷积)

    剩下的就是一些优化了...

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    using namespace std;
    #define N 50005
    #define mod 19940417
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ll long long
    int C[N][21],a[N],n,Q;
    char s[10];
    struct node
    {
    	ll f[21],tag,add;
    	int siz;
    	node ()
    	{
    		memset(f,0,sizeof(f));
    		siz=tag=add=0;
    	}
    	node operator +(const node &b)
    	{
    		node c;
    		c.f[0]=1;
    		for(int i=1;i<=20;i++)
    		{
    			for(int j=0;j<=i;j++)
    			{
    				c.f[i]+=f[j]*b.f[i-j]%mod;
    				c.f[i]%=mod;
    			}
    		}
    		c.siz=siz+b.siz;
    		return c;
    	}
    	void plus(ll x)
    	{
    		add+=x;
    		add%=mod;
    		for(int i=min(siz,20);i;i--)
    		{
    			ll y=x;
    			for(int j=1;j<=i;j++)
    			{
    				f[i]=(f[i]+y*f[i-j]%mod*C[siz-i+j][j]%mod)%mod;
    				y=y*x%mod;
    			}
    		}
    	}
    	void rev()
    	{
    		tag^=1;
    		add=(mod-add)%mod;
    		for(int i=min(siz,20);i;i--)
    		{
    			if(i&1)f[i]=(mod-f[i])%mod;
    		}
    	}
    }tr[N<<2];
    void PushUp(int rt)
    {
    	tr[rt]=tr[rt<<1]+tr[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
    	if(l==r)
    	{
    		tr[rt].f[1]=a[l];
    		tr[rt].f[0]=tr[rt].siz=1;
    		return ;
    	}
    	int m=(l+r)>>1;
    	build(lson);
    	build(rson);
    	PushUp(rt);
    }
    void PushDown(int rt)
    {
    	if(tr[rt].tag)
    	{
    		tr[rt<<1].rev();
    		tr[rt<<1|1].rev();
    		tr[rt].tag=0;
    	}
    	if(tr[rt].add)
    	{
    		tr[rt<<1].plus(tr[rt].add);
    		tr[rt<<1|1].plus(tr[rt].add);
    		tr[rt].add=0;
    	}
    }
    void Update(int L,int R,int c,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		tr[rt].plus(c);
    		return ;
    	}
    	PushDown(rt);
    	int m=(l+r)>>1;
    	if(m>=L)Update(L,R,c,lson);
    	if(m<R)Update(L,R,c,rson);
    	PushUp(rt);
    }
    void Update_rev(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		tr[rt].rev();
    		return ;
    	}
    	PushDown(rt);
    	int m=(l+r)>>1;
    	if(m>=L)Update_rev(L,R,lson);
    	if(m<R)Update_rev(L,R,rson);
    	PushUp(rt);
    }
    node query(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		return tr[rt];
    	}
    	PushDown(rt);
    	int m=(l+r)>>1;
    	if(m>=R)return query(L,R,lson);
    	if(m<L)return query(L,R,rson);
    	return query(L,R,lson)+query(L,R,rson);
    }
    int main()
    {
    	scanf("%d%d",&n,&Q);
    	C[0][0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		C[i][0]=1;
    		for(int j=1;j<=20;j++)
    		{
    			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	build(1,n,1);
    	while(Q--)
    	{
    		int x,y,z;
    		scanf("%s%d%d",s,&x,&y);
    		if(s[0]=='I')
    		{
    			scanf("%d",&z);
    			Update(x,y,z,1,n,1);
    		}else if(s[0]=='R')
    		{
    			Update_rev(x,y,1,n,1);
    		}else
    		{
    			scanf("%d",&z);
    			printf("%lld
    ",(query(x,y,1,n,1).f[z]+mod)%mod);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    几何服务,cut功能,输入要素target(修改后)内容。
    几何服务,cut功能,输入要素target(修改前)内容。
    ArcGIS Server,rest路径输入要素json 格式描述
    window对象的screen详解
    window对象的inner/outer/page/screen详解
    js的scroll详解
    js的client详解
    自己封装的操作DOM方法
    js模拟高级语言的重载
    charCode与keyCode的区别
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9042787.html
Copyright © 2011-2022 走看看