• [bzoj1558][JSOI2009]等差数列


    题目:给定n个数,m个操作,每次给一段区间加一个等差数列或者询问一段区间至少要用多少个等差数列来表示。$n,mleqslant 10^{5}$

    题解:老套路,维护差分数组,修改操作变成了两个单点加和一个区间加。然后我们用线段树维护,合并答案的时候复杂一点,s[0/1][0/1]表示左右端点取不取的答案就行啦。

    #include<iostream>
    #include<cstdio>
    #define MN 100000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,q,s[MN+5];
    char op[4];
    
    inline void re(int&x,int y){if(y<x) x=y;}
    
    struct data
    {
        int s[4],l,r;
        data operator + (data y)
        {
            data c;c.l=l;c.r=y.r;
            c.s[0]=s[2]+y.s[1]-(r==y.l);
            re(c.s[0],s[0]+y.s[1]);re(c.s[0],s[2]+y.s[0]);
            c.s[1]=s[3]+y.s[1]-(r==y.l);
            re(c.s[1],s[1]+y.s[1]);re(c.s[1],s[3]+y.s[0]);
            c.s[2]=s[2]+y.s[3]-(r==y.l);
            re(c.s[2],s[2]+y.s[2]);re(c.s[2],s[0]+y.s[3]);
            c.s[3]=s[3]+y.s[3]-(r==y.l);
            re(c.s[3],s[3]+y.s[2]);re(c.s[3],s[1]+y.s[3]); 
            return c;
        }
    }; 
    struct node{
        int l,r,val;data x;
    }T[MN*4+5];
    
    void pushdown(int x)
    {
        int l=x<<1,r=x<<1|1;
        T[l].val+=T[x].val;T[r].val+=T[x].val;
        T[l].x.l+=T[x].val;T[l].x.r+=T[x].val;
        T[r].x.l+=T[x].val;T[r].x.r+=T[x].val;
        T[x].val=0;
    }
    
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)) 
        {    
            T[x].x.s[0]=0;T[x].x.l=T[x].x.r=s[l];
            T[x].x.s[1]=T[x].x.s[3]=T[x].x.s[2]=1;
            return;
        }
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    data query(int x,int l,int r)
    {
        //cout<<"query"<<x<<" "<<l<<" "<<r<<" "<<T[x].l<<" "<<T[x].r<<endl;
        if(T[x].l==l&&T[x].r==r) return T[x].x;
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) return query(x<<1,l,r);
        else if(l>mid) return query(x<<1|1,l,r);
        else return query(x<<1,l,mid)+query(x<<1|1,mid+1,r);
    }
    
    void modify(int x,int l,int r,int ad)
    {
        if(T[x].l==l&&T[x].r==r)
        {
            T[x].val+=ad;T[x].x.l+=ad;T[x].x.r+=ad;
            return;
        }
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) modify(x<<1,l,r,ad);
        else if(l>mid) modify(x<<1|1,l,r,ad);
        else modify(x<<1,l,mid,ad),modify(x<<1|1,mid+1,r,ad); 
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) s[i]=read();    
        for(int i=1;i<n;i++) s[i]=s[i+1]-s[i];
        build(1,1,n-1);
        for(q=read();q;q--)
        {
            scanf("%s",op);int l=read(),r=read();
            if(op[0]=='B') l==r?puts("1"):printf("%d
    ",query(1,l,r-1).s[3]);
            else
            {
                int a=read(),b=read();
                if(l!=1) modify(1,l-1,l-1,a);
                if(l!=r) modify(1,l,r-1,b);
                if(r!=n) modify(1,r,r,-(a+(r-l)*b));    
            }
        }
        return 0;
    }
  • 相关阅读:
    笔试算法题(45):简介
    笔试算法题(44):简介
    笔试算法题(43):布隆过滤器(Bloom Filter)
    笔试算法题(42):线段树(区间树,Interval Tree)
    笔试算法题(41):线索二叉树(Threaded Binary Tree)
    笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)
    笔试算法题(39):Trie树(Trie Tree or Prefix Tree)
    笔试算法题(38):并查集(Union-Find Sets)
    笔试算法题(37):二叉树的层序遍历 & 最长递增的数字串
    mysql cmd 启动服务
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1558.html
Copyright © 2020-2023  润新知