zoukankan      html  css  js  c++  java
  • 1540-线段树区间合并操作

    #include<stdio.h>
    #include<iostream>
    #include<stack>
    #include<cstring>
    using namespace std;
    const int MAX=1000000;
    struct pr {
        int lsum,rsum,msum;
        int left,right;                   
    }tr[MAX+10];
    int n,m;
    inline int ll(int k) {return 2*k;}          
    inline int rr(int k) {return 2*k+1;}         
    inline int mid(int kk1,int kk2) {return (kk1+kk2)>>1;}
    
    
    void pushup(int k){//m=r-l+1;
        int l=tr[k].left,r=tr[k].right;
        int mi=mid(l,r);
        tr[k].lsum =tr[ll(k)].lsum;
        tr[k].rsum =tr[rr(k)].rsum;
        if (tr[k].lsum == mi-l+1) tr[k].lsum+=tr[rr(k)].lsum;
        if (tr[k].rsum == r-mi) tr[k].rsum+=tr[ll(k)].rsum;
        tr[k].msum = max(tr[rr(k)].lsum+tr[ll(k)].rsum,max(tr[ll(k)].msum,tr[rr(k)].msum));
        return;
    }
    
    
    void build(int k,int s,int t) {
        tr[k].left=s;tr[k].right=t;
        if(s==t) {tr[k].rsum=tr[k].lsum=tr[k].msum=1;return;}               
        build(ll(k),s,mid(s,t));
        build(rr(k),mid(s,t)+1,t);
        pushup(k);        //pushup
    }
    
    void modify(int k,int in,int x) {
        int l=tr[k].left,r=tr[k].right;
        if(l==r) {
            if(x==1)
                tr[k].lsum=tr[k].msum=tr[k].rsum=0;
            else
                tr[k].lsum=tr[k].msum=tr[k].rsum=1;
            return ;
        }
        int mi=mid(l,r);
        if(in<=mi) modify(ll(k),in,x);
        else if(in>mi) modify(rr(k),in,x);
        pushup(k);
    }
    
    int query(int k,int x) {
        int l=tr[k].left,r=tr[k].right;
        if(l==r||tr[k].msum==0||tr[k].msum==r-l+1) return tr[k].msum;
    
        int mi=mid(l,r);
        int res=0;
        if (x<=mi){
            if(tr[ll(k)].right-tr[ll(k)].rsum+1<=x)
                res=query(ll(k),x)+query(rr(k),mi+1);
            else
                res=query(ll(k),x);
        }
        else if(x>mi){
            if(tr[rr(k)].lsum+tr[rr(k)].left-1>=x)
                res=query(rr(k),x)+query(ll(k),mi);
            else
                res=query(rr(k),x);
        }
        return res;
    }
    
    
    int main()
    {
        while(cin>>n>>m){
            build(1,1,n);
            char s[10];
            int x;
            stack<int> Q;
            for(int i=0;i<m;i++){
                scanf("%s",s);
                if(s[0]=='D'){
                    scanf("%d",&x);
                    Q.push(x);
                    modify(1,x,1);
                }
                else if(s[0]=='Q'){
                    scanf("%d",&x);
                    printf("%d
    ",query(1,x));
                }
                else{
                    int y=Q.top();
                    Q.pop();
                    modify(1,y,0);
                }
            }
    
        }
        return 0;
    }


    这是一道基础的线段树合并基本操作。

    题意就是单点修改,然后查询单点所在的连续合法区间,初始化都是合法的。

    这题的考点应该就是查询部分。

    查询部分单独拿出来说一下,

    if (x<=mi){
            if(tr[ll(k)].right-tr[ll(k)].rsum+1<=x)
                res=query(ll(k),x)+query(rr(k),mi+1);
            else
                res=query(ll(k),x);
        }

    就拿查询点在mid的左来举个栗子,考虑到在左面如果只查询左区间很可能得到错误答案(例如x在rsum里那么q(x)的答案就会漏掉r右边的部分),所以在另一个区间查他的左端点就可以啦,所以这题大致就是这样的了。。其他类比就行了。。

    蒟蒻写的搓大家见谅。。。继续努力。。鲤鱼王加油!

  • 相关阅读:
    springboot整合springmvc原理
    springboot Thymeleaf
    springboot 首页处理
    springboot整合Druid
    springboot 整合JDBC
    CentOS安装Mysql
    springboot 多环境切换
    springboot JSR303数据校验
    【转载】WEB架构师成长之路
    一些想法
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672587.html
Copyright © 2011-2022 走看看