• bzoj 2962 序列操作 —— 线段树


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962

    维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可;

    取反只需要把奇数个数的乘积和变成相反数即可;

    关键是区间 + k:比如对于一个元素,原来是 a, b, c,+ k 变成 (a+k), (b+k), (c+k)

    从每个括号里选 a,b,c 或者 k,如果选 j 个 k ,那么就是 sum[i] += sum[i-j] * k^j * C(len-(i-j), j),组合数表示从剩余的位置中选 j 个 k;

    详细可以看这个博客:https://blog.csdn.net/qq_35866453/article/details/77998472

    注意一下处理 rev 标记和 lzy 标记,顺序是先 reverse 再 add,更改 rev 标记时要把 lzy 标记取反;

    调了一上午:

    1.各种计算 sum 时,上限原来写的是20,又觉得不好,改成 len,然而应该是 min(len,20) ...

    2.query 写得不好的话会 TLE ... 还是模仿了 Narh 的写法,感觉很优秀。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    int const xn=5e4+5,mod=19940417;
    int n,q,cnt=1,a[xn],lzy[xn<<1],ans[xn];
    ll c[xn][25];
    bool rev[xn<<1];
    char ch;
    struct N{int ls,rs,len; ll sum[25];}t[xn<<1];
    int rd()
    {
        int ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    void init()
    {
        for(int i=0;i<=n;i++)c[i][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=min(i,20);j++)
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    ll pls(ll a,ll b){a=a+b; while(a>=mod)a-=mod; while(a<0)a+=mod; return a;}
    void pushup(int x)
    {
        int ls=t[x].ls,rs=t[x].rs,lm=min(t[x].len,20);
        for(int i=1;i<=lm;i++)//min!! 
        {
            t[x].sum[i]=0;
            for(int j=0;j<=i;j++)
                t[x].sum[i]=pls(t[x].sum[i],(t[ls].sum[j]*t[rs].sum[i-j])%mod);
        }
    }
    void ad(int x,int k)
    {
        int len=t[x].len,lm=min(len,20);
        for(int i=lm;i>=1;i--)//min  
            for(int j=1,pw=k;j<=i;j++,pw=((ll)pw*k)%mod)//
                t[x].sum[i]=pls(t[x].sum[i],t[x].sum[i-j]*pw%mod*c[len-i+j][j]%mod);
        lzy[x]=pls(lzy[x],k);
    }
    void re(int x)
    {
        int lm=min(t[x].len,20);
        for(int i=1;i<=lm;i+=2)t[x].sum[i]=pls(mod,-t[x].sum[i]);//min
        rev[x]^=1;
        lzy[x]=pls(mod,-lzy[x]);
    }
    void pushdown(int x)
    {
        int ls=t[x].ls,rs=t[x].rs;
        if(rev[x])re(ls),re(rs),rev[x]=0;
        if(lzy[x])ad(ls,lzy[x]),ad(rs,lzy[x]),lzy[x]=0;
    }
    void build(int x,int l,int r)
    {
        t[x].sum[0]=1; t[x].len=r-l+1;
        if(l==r){t[x].sum[1]=a[l]; return;}
        t[x].ls=++cnt; t[x].rs=++cnt;
        int ls=t[x].ls,rs=t[x].rs;
        build(ls,l,mid); build(rs,mid+1,r);
        pushup(x);
    }
    void add(int x,int l,int r,int L,int R,int k)
    {
        if(l>=L&&r<=R){ad(x,k); return;}
        pushdown(x);
        int ls=t[x].ls,rs=t[x].rs;
        if(mid>=L)add(ls,l,mid,L,R,k);
        if(mid<R)add(rs,mid+1,r,L,R,k);
        pushup(x);
    }
    void reverse(int x,int l,int r,int L,int R)
    {
        if(l>=L&&r<=R){re(x); return;}
        pushdown(x);
        int ls=t[x].ls,rs=t[x].rs;
        if(mid>=L)reverse(ls,l,mid,L,R);
        if(mid<R)reverse(rs,mid+1,r,L,R);
        pushup(x);
    }
    /*
    ll query(int x,int l,int r,int L,int R,int k)
    {
        int ls=t[x].ls,rs=t[x].rs;
        if(l>=L&&r<=R)return t[x].sum[k];
        pushdown(x);
        if(mid>=R)return query(ls,l,mid,L,R,k);
        else if(mid<L)return query(rs,mid+1,r,L,R,k);
        else
        {
            ll ret=0;
            for(int i=0;i<=k;i++)
                ret=pls(ret,query(ls,l,mid,L,R,i)*query(rs,mid+1,r,L,R,k-i)%mod);
            return ret;
        }
    }
    */
    void query(int cr,int l,int r,int L,int R,int k)
    {
        if(l>=L&&r<=R)
        {
            int lm=min(k,r-l+1);
            for(int i=k;i>=0;i--)
                for(int j=1;j<=lm&&j<=i;j++)//j<=i
                    ans[i]=((ll)ans[i]+t[cr].sum[j]*ans[i-j])%mod;
            return;
        }
    
        pushdown(cr);
        if(L<=mid) query(t[cr].ls,l,mid,L,R,k);
        if(mid<R) query(t[cr].rs,mid+1,r,L,R,k);
    }
    
    int main()
    {
        n=rd(); q=rd();
        init();
        for(int i=1;i<=n;i++)a[i]=rd();
        build(1,1,n);
        ans[0]=1;
        for(int i=1,a,b,c;i<=q;i++)
        {
            cin>>ch;
            a=rd(); b=rd();
            if(ch!='R')c=rd();
            if(ch=='I')c=pls(c,0),add(1,1,n,a,b,c);
            if(ch=='R')reverse(1,1,n,a,b);
            if(ch=='Q')
    //            printf("%lld
    ",query(1,1,n,a,b,c)%mod);
            
            {
                for(int i=1;i<=c;i++)ans[i]=0;
                query(1,1,n,a,b,c);
                printf("%d
    ",ans[c]);
            }
            
        }
        return 0;
    }
  • 相关阅读:
    安卓表格布局android:collapseColumns,android:shrinkColumns和stretchColumn
    Cocos2dx 学习记录 [2] 关于混合和高亮一些知识点的体会
    01背包问题
    textarea文本域宽度和高度(width、height)自己主动适应变化处理
    SSL协议具体解释
    Geeks Union-Find Algorithm Union By Rank and Path Compression 图环算法
    Linux内核源代码分析方法
    linux服务之svn
    java实现第七届蓝桥杯冰雹数
    java实现第七届蓝桥杯冰雹数
  • 原文地址:https://www.cnblogs.com/Zinn/p/9722607.html
Copyright © 2020-2023  润新知