zoukankan      html  css  js  c++  java
  • 线段树树状数组小结

    7-14 Yet Another Bracket Sequence

    给定一个序列,m次改变序列,问序列是否括号匹配。

    把(看做+1,)看做-1,那么括号匹配的条件即为1到n的区间最小前缀和为0,且pre[ n ] 为0,用线段树模拟即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5+500;
    int pre[N];
    struct node{
      int s,l,r,lz;
    }tree[N<<2];
    void push_up(int x){
      tree[x].s=min(tree[x<<1].s,tree[x<<1|1].s);
    }
    void push_down(int x){
      if(!tree[x].lz)return ;
      tree[x<<1].s+=tree[x].lz,tree[x<<1|1].s+=tree[x].lz;
      tree[x<<1].lz+=tree[x].lz,tree[x<<1|1].lz+=tree[x].lz;
      tree[x].lz=0;
    }
    
    void build(int x,int l,int r){
      tree[x].l=l;tree[x].r=r;
      if(l==r){
        tree[x].s=pre[l];
        return ;
      }
      int mid=(l+r)>>1;
      build(x<<1,l,mid);
      build(x<<1|1,mid+1,r);
      push_up(x);
    }
    
    void modify(int x,int l,int r,int val){
        if(tree[x].l>=l&&tree[x].r<=r){
          tree[x].lz+=val;
          tree[x].s+=val;
          return ;
        }  
        push_down(x);
        int mid=(tree[x].l+tree[x].r)>>1;
        if(l<=mid)modify(x<<1,l,r,val);
        if(r>mid)modify(x<<1|1,l,r,val);
        push_up(x);
    }
    char s[N];
    int main(){
        int n,m;
        scanf("%d %d %s",&n,&m,s+1);
        pre[0]=0;
        for(int i=1;i<=n;i++){
          if(s[i]=='(')pre[i]=pre[i-1]+1;
          else pre[i]=pre[i-1]-1;
        }
        
        // for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(s[i]=='(')?1:-1;
        
        int sum=pre[n];
        build(1,1,n);
        
        while(m--){
          int x;scanf("%d",&x);
    
          if(s[x]=='(')s[x]=')',sum-=2,modify(1,x,n,-2);
          else s[x]='(',sum+=2,modify(1,x,n,2);
          // cout<<"test : "<<tree[1].s<<" "<<sum<<endl;
          if(tree[1].s==0&&sum==0)puts("Yes");
          else puts("No");
        }
    
        // system("pause");
      return 0;
    }
    View Code

    Can you answer these queries III

    单点修改和询问区间最大子串和,设置  lmax 和 rmax,合并即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+500;
    typedef long long ll;
    const int inf=1e9;
    struct node{
      int l,r;
      int sum,val,lmax,rmax;
      node(){
      val=lmax=rmax=-inf;
        l=r=sum=0;
      }
    }tree[N<<2];
    int a[N];
    
    void push_up(int x){
    
      tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
      tree[x].lmax=max(tree[x<<1].lmax,tree[x<<1].sum+tree[x<<1|1].lmax);
      tree[x].rmax=max(tree[x<<1|1].rmax,tree[x<<1|1].sum+tree[x<<1].rmax);
      tree[x].val=max(max(tree[x<<1].val,tree[x<<1|1].val),tree[x<<1].rmax+tree[x<<1|1].lmax);
    
    }
    
    
    void build(int x,int l,int r){
      // cout<<x<<endl;
      tree[x].l=l;tree[x].r=r;
      
      if(l==r){
        tree[x].sum=tree[x].lmax=tree[x].rmax=tree[x].val=a[l];
        return ;
      }
    
      int mid=(l+r)>>1;
      build(x<<1,l,mid);
      build(x<<1|1,mid+1,r);
      push_up(x);
    
    }
    
    void modify(int x,int rt){
    
        if(tree[rt].l==tree[rt].r){
    
        tree[rt].sum=tree[rt].lmax=tree[rt].rmax=tree[rt].val=a[x];
        return ;
    
        }
    
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if(x<=mid)modify(x,rt<<1);
        else modify(x,rt<<1|1);
        push_up(rt);
    
    }
    
    
    node query(int a,int b,int rt){
    
      if(tree[rt].l>=a&&tree[rt].r<=b){
        return tree[rt];
      }
      int mid=(tree[rt].l+tree[rt].r)>>1;
      node lnode,rnode,ret;
      
      if(a<=mid){
        lnode=query(a,b,rt<<1);
    
      }
      if(b>mid){
        rnode=query(a,b,rt<<1|1);
      }
    
      ret.sum=lnode.sum+rnode.sum;
      ret.lmax=max(lnode.lmax,lnode.sum+rnode.lmax);
      ret.rmax=max(rnode.rmax,rnode.sum+lnode.rmax);
      ret.val=max(max(lnode.val,rnode.val),lnode.rmax+rnode.lmax);  
    
      return ret;
    
    }
    
    int main(){ 
      
      int n,m;cin>>n>>m;
    
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      
      build(1,1,n);
    
      while(m--){
        int k,x,y;
        scanf("%d %d %d",&k,&x,&y);
    
        if(k==1){
    
          if(x>y)swap(x,y);
          printf("%d
    ",query(x,y,1).val);
    
        }
    
        else {
    
          a[x]=y;
          modify(x,1);
    
        }
    
    
      }
      // system("pause");
    
      return 0;
    }
    View Code

    Can you answer these queries III

    实现区间加,询问区间gcd。

    有区间加的形式,无法直接维护区间gcd。

    考虑辗转相除法,gcd($x$,$y$,$z$)=gcd($x$,$y-x$,$z-y$)

    对于区间加:让差分数组$b_l$+$d$,$b_{r+1}$-$d$

    对于区间gcd,gcd[l,r]=gcd($a_l$,gcd[ b [l+1,r] ] )

    用一个线段树维护差分数组,支持区间gcd和单点修改

    考虑数组a动态变化,需要支持区间加和单点查询,用一个树状数组模拟,

    在维护差分数组的区间gcd会出现负数的情况,取绝对值即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define int long long 
    const int N=6e5+500;
    int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    int a[N],b[N];
    struct node{
      int g,l,r;
    }tree[N<<4];
    
    void push_up(int x){
      tree[x].g=gcd(tree[x<<1].g,tree[x<<1|1].g);
    }
    
    void build(int x,int l,int r){
      tree[x].l=l;tree[x].r=r;
      if(l==r){
        tree[x].g=b[l];
        return ;
      }
      int mid=(l+r)>>1;
      build(x<<1,l,mid);
      build(x<<1|1,mid+1,r);
      push_up(x);
    }
    
    void modify(int rt,int x,int d){
    
      if(tree[rt].l==x&&tree[rt].r==x){
        tree[rt].g+=d;
        return ;
      }
      
      int mid=(tree[rt].l+tree[rt].r)>>1;
      if(x<=mid)modify(rt<<1,x,d);
      else if(x>mid)modify(rt<<1|1,x,d);
      push_up(rt);
    
    }
    
    int query(int x,int l,int r){
      
      if(tree[x].l>=l&&tree[x].r<=r){
        return tree[x].g;
      }
    
      int mid=(tree[x].l+tree[x].r)>>1;
      if(r<=mid)return query(x<<1,l,r);
      if(l>mid)return query(x<<1|1,l,r);
      return abs( gcd(query(x<<1,l,r),query(x<<1|1,l,r)) );
    
    }
    
    int T[N];
    #define lowbit(x)(x&-x)
    int n,m;
    void add(int x,int d){
      for(;x<=n;x+=lowbit(x))T[x]+=d;
    }
    int Sum(int x){
      int sum=0;
      for(;x;x-=lowbit(x))sum+=T[x];
      return sum;
    }
    
    signed main(){
    
      scanf("%lld %ld",&n,&m);
      // cin>>n>>m;
      
      for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
      b[1]=a[1];                
      add(1,b[1]);
    
      for(int i=2;i<=n;i++)b[i]=a[i]-a[i-1],add(i,b[i]);
    
      build(1,1,n);
      
      while(m--){
        char op;int x,y,z;
        getchar();
        scanf("%c",&op);
        // cout<<"test :"<<op<<endl;
        if(op=='C'){
          scanf("%lld %lld %lld",&x,&y,&z);
          modify(1,x,z);add(x,z);
          if(y+1<=n)modify(1,y+1,-z),add(y+1,-z);
        }
    
        else {
          scanf("%lld %lld",&x,&y);
          // cout<<"ans :";
          if(x==y)printf("%lld
    ",Sum(x));
          else printf("%lld
    ",gcd( Sum(x),query(1,x+1,y) ) );
        }
    
      }
    
      // system("pause");
      return 0;
    }
    View Code

    楼兰图腾

    树状数组维护逆序对即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=8e5+500;
    #define lowbit(x)(x&-x)
    typedef long long ll;
    ll tree[N],y[N],l[N],r[N];
    int n;
    void init(){
        memset(tree,0,sizeof tree);
        // memset(l,0,sizeof l);
        // memset(r,0,sizeof r);
    }
    
    void add(int x,ll d){
        for(;x<=n;x+=lowbit(x))tree[x]+=d;
    }
    
    ll ask(int x){
        ll sum=0;
        for(;x;x-=lowbit(x))sum+=tree[x];
        return sum;
    }
    
    int  main(){
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%d",&y[i]);
            ll ans1=0,ans2=0;
        init();
        
        for(int i=1;i<=n;i++){
            l[i]=max(0ll,(i-1)-ask(y[i]));
            add(y[i],1);
        }
    
        init();
        for(int i=n;i>=1;i--){
            r[i]=max(0ll,(n-i)-ask(y[i]));
            add(y[i],1);
        }
        for(int i=1;i<=n;i++)ans1+=l[i]*r[i];
    
        init();
        
        for(int i=1;i<=n;i++){
            l[i]=ask(y[i]-1);
            add(y[i],1);
        }
    
        init();
        
        for(int i=n;i>=1;i--){
            r[i]=ask(y[i]-1);
            add(y[i],1);
        }
    
        for(int i=1;i<=n;i++)ans2+=l[i]*r[i];
            cout<<ans1<<" "<<ans2<<endl;
    
        // system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    团队作业(七)
    8848小分队:个人最终总结
    团队作业(四)
    参与团队编程的讨论郝一的角度
    团队作业(五)
    团队作业(三)
    团队作业(二)
    团队题目的确立与小组分工
    xJuujMbXeB
    团队作业汇报
  • 原文地址:https://www.cnblogs.com/littlerita/p/13906642.html
Copyright © 2011-2022 走看看