zoukankan      html  css  js  c++  java
  • [清华集训]序列操作

    写了这么多数据结构题,一半左右是线段树
    线段树真是优秀啊

    题意

    有一个长度为n的序列,有三个操作:

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

    首先考虑维护哪些信息
    显然需要维护一个数组表示答案

    然后考虑合并
    显然
    (f[rt][n]=f[ls][n]+f[rs][n]+sum_{i=1}^{n-1}{f[ls][i]*f[rs][n-i]})

    再考虑维护哪些标记
    区间加法,区间反转

    考虑标记的维护
    显然先维护反转标记后维护加法标记

    最后考虑修改答案
    区间反转只需把乘奇数个数的答案反转
    区间加法类似二项式定理可以推出(好吧其实和二项式定理没有什么关系)
    (f[rt][n]=f[rt][n]+ sum_{i=1}^{n-1}{f[rt][j]*C_{size-j}^{i-j}* k^i } + C_{size}^i * k^n)
    因为前面的值会影响后面的,所以从后往前更新

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define gc c=getchar()
    #define r(x) read(x)
    #define ll long long
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    
    template<typename T>
    inline void read(T&x){
        x=0;T k=1;char gc;
        while(!isdigit(c)){if(c=='-')k=-1;gc;}
        while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
    }
    
    const int N=1e5+7;
    const int p=19940417;
    
    ll C[N][21];
    
    struct Seg{
        bool tag1;
        ll tag2,a[21];
        int siz;
        
        Seg(){
            tag1=0;
            tag2=0;
            memset(a,0,sizeof(a));
            siz=1;
        }
        
        inline const ll& operator [](const int &x)const{
            return a[x];
        }
        
        inline ll& operator [](const int &x){
            return a[x];
        }
        
        inline void reverse(){
        	tag1^=1;
        	if(tag2)tag2=p-tag2;
        	for(int i=1;i<20;i+=2)if(a[i])a[i]=p-a[i];
        }
        
        inline void increase(int x){
        	(tag2+=x)%=p;
            for(int i=min(20,siz);i;--i){
                ll Tmp=x;
                for(int j=i-1;j;--j,(Tmp*=x)%=p){
                    (a[i]+=Tmp*a[j]%p*C[siz-j][i-j]%p)%=p;
                }
                (a[i]+=C[siz][i]*Tmp)%=p;
            }
        }
        	
    }tr[N<<2];
    
    inline Seg operator + (const Seg &a,const Seg &b){
        Seg ret;
        ret[0]=1;
        ret.siz=a.siz+b.siz;
        for(int i=1;i<=min(ret.siz,20);++i){
            ret[i]=(a[i]+b[i])%p;
            for(int j=1;j<i;++j){
                (ret[i]+=a[j]*b[i-j])%=p;
            }
        }
        return ret;
    }
    
    inline void update(int rt){
        tr[rt]=tr[ls]+tr[rs];
    }
    
    inline void pushdown(int rt){
        if(tr[rt].tag1){
            tr[ls].reverse();
            tr[rs].reverse();
            tr[rt].tag1=0;
        }
        if(tr[rt].tag2){
            tr[ls].increase(tr[rt].tag2);
            tr[rs].increase(tr[rt].tag2);
            tr[rt].tag2=0;
        }
    }
    
    int a[N];
    
    void build(int rt,int l,int r){
        if(l==r){
            tr[rt][0]=1;
            tr[rt][1]=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        update(rt);
    }
    
    void reverse(int rt,int l,int r,int x,int y){
        if(x<=l&&r<=y){
            tr[rt].reverse();
            return;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(x<=mid)reverse(ls,l,mid,x,y);
        if(y>mid)reverse(rs,mid+1,r,x,y);
        update(rt);
    }
    
    void increase(int rt,int l,int r,int x,int y,int v){
        if(x<=l&&r<=y){
            tr[rt].increase(v);
            return;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(x<=mid)increase(ls,l,mid,x,y,v);
        if(y>mid)increase(rs,mid+1,r,x,y,v);
        update(rt);
    }
    
    Seg query(int rt,int l,int r,int x,int y){
        if(x<=l&&r<=y)return tr[rt];
        pushdown(rt);
        int mid=(l+r)>>1;
        if(y<=mid)return query(ls,l,mid,x,y);
        else if(x>mid)return query(rs,mid+1,r,x,y);
        else return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
    }
    
    inline void pre(int n){
        for(int i=0;i<=n;++i){
            C[i][0]=C[i][i]=1;
            for(int j=1;j<=min(i-1,20);++j){
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
            }
        }
    }
    
    int main(){
        int n,q;r(n),r(q);pre(n);
        for(int i=1;i<=n;++i)r(a[i]),a[i]=(a[i]%p+p)%p;
        build(1,1,n);
        while(q--){
            char opt[5];scanf("%s",opt);
            int l,r,x;r(l),r(r);
            switch(opt[0]){
                case 'I':{r(x);x=(x%p+p)%p;increase(1,1,n,l,r,x);break;}
                case 'R':{reverse(1,1,n,l,r);break;}
                case 'Q':{r(x),printf("%lld
    ",query(1,1,n,l,r)[x]);break;}
            }
        }
    }
    
    
  • 相关阅读:
    博客备份小工具3
    博客转发小工具1
    04-属性选择器
    05-伪类选择器
    03-高级选择器
    02-css的选择器
    01-css的引入方式
    函数进阶-(命名空间、作用域、函数嵌套、作用域链、函数名本质、闭包)
    函数基础-(引子、定义函数、调用函数、函数返回值、函数参数)
    Python之路【第08章】:Python函数
  • 原文地址:https://www.cnblogs.com/yicongli/p/9839783.html
Copyright © 2011-2022 走看看