• zoj3299 线段树区间更新,坐标建立线段树的方式


    /*
    平台和砖块的坐标离散化,边缘坐标转换成单位长度
    处理下落信息,sum数组维护区间的砖块数量
    把平台按高度从高到低排序,询问平台区间的砖块有多少,询问后将该区域砖块数置0
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 100005
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ll long long 
    struct Blocks{
        int l,r;
    }bks[maxn];//砖块信息
    struct Boards{
        int l,r,h,id;
        bool operator<(const Boards & a)const{
            return h>a.h;
        }
    }bds[maxn];//平台信息
    ll ans[maxn];
    int data[maxn<<3],cnt,tot;//离散化
    ll sum[maxn<<2],lazy[maxn],flag[maxn];//flag维护区间是否置零,优先级大于lazy
    inline void pushup(int rt){
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    inline void pushdown(int l,int r,int rt){
        if(flag[rt]){
            sum[rt<<1]=sum[rt<<1|1]=0;
            flag[rt<<1]=flag[rt<<1|1]=1;
            flag[rt]=0;
        }
        else if(lazy[rt]){
            int m=l+r>>1;
            lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
            sum[rt<<1]+=lazy[rt]*(data[m]-data[l]+1);
            sum[rt<<1|1]+=lazy[rt]*(data[r]-data[m]);
            lazy[rt]=0;
        }
    }
    void setzero(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r){
            sum[rt]=0;
            lazy[rt]=0;
            flag[rt]=1;
            return;
        }
        pushdown(l,r,rt);
        int m=l+r>>1;
        if(L<=m) setzero(L,R,lson);
        if(R>m) setzero(L,R,rson);
        pushup(rt);
    }
    void build(int l,int r,int rt){
        sum[rt]=lazy[rt]=flag[rt]=0;
        if(l==r) return;
        int m=l+r>>1;
        build(lson);build(rson);
    }
    void update(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r){
            lazy[rt]++;
            sum[rt]+=data[r]-data[l]+1;
            return;
        }
        pushdown(l,r,rt);
        int m=l+r>>1;
        if(L<=m) update(L,R,lson);
        if(R>m) update(L,R,rson);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r){
            return sum[rt];
        }
        pushdown(l,r,rt);
        int m=l+r>>1;
        ll ret=0;
        if(L<=m) ret+=query(L,R,lson);
        if(R>m) ret+=query(L,R,rson);
        return ret;
    }
    int main(){
        int n,m;
        while(scanf("%d%d",&n,&m)==2){
            tot=cnt=0;
            for(int i=0;i<n;i++){
                scanf("%d%d",&bks[i].l,&bks[i].r);
                bks[i].r--;
                data[cnt++]=bks[i].l;
                data[cnt++]=bks[i].r;
            }
            for(int i=0;i<m;i++){
                scanf("%d%d%d",&bds[i].l,&bds[i].r,&bds[i].h);
                bds[i].id=i;
                bds[i].r--;
                data[cnt++]=bds[i].l;
                data[cnt++]=bds[i].r;
            }
            int tmp=cnt;
            sort(data,data+cnt);
            for(int i=1;i<cnt;i++)
                if(data[i]-data[i-1]>1) data[tmp++]=data[i-1]+1;
            cnt=tmp;
            sort(data,data+cnt);
            tot=unique(data,data+cnt)-data;
            sort(bds,bds+m);
    
            build(0,tot,1);
            for(int i=0;i<n;i++){
                int L=lower_bound(data,data+tot,bks[i].l)-data;
                int R=lower_bound(data,data+tot,bks[i].r)-data;
                update(L,R,0,tot,1);
            }
            //每次查询后
            for(int i=0;i<m;i++){
                int L=lower_bound(data,data+tot,bds[i].l)-data;
                int R=lower_bound(data,data+tot,bds[i].r)-data;
                ans[bds[i].id]=query(L,R,0,tot,1);
                setzero(L,R,0,tot,1);
            }
            for(int i=0;i<m;i++)
                printf("%lld
    ",ans[i]);
        }
    }

     碰到区间更新最头痛的就是坐标的离散化,所以上面的代码挂了

    网上看题解,线段树有直接维护坐标的办法,但是维护方式和普通的区间更新略有不同

    同时换了种比较容易懂的思路

    /*
    对于坐标轴上的离散化,与段的离散化有所不同,但也可以直接离散化而不用进行其它修改,其在线段树上的维护方式为[l,m],[m,r],同时分左右子树进行更新时判断条件也相应改变
    比较快的做法,给横轴染色,然后再统计掉在每种颜色的砖头有几块
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define maxn 100005
    #define ll long long 
    struct board{
        int l,r,h,id;
    }b[maxn];
    int n,m,l[maxn],r[maxn];
    ll res[maxn];
    ll sum[maxn<<4],flag[maxn<<4];
    vector<int> a;
    bool cmp(const board &a,const board &b){
        return a.h<b.h;
    }
    void pushdown(int k){
        if(flag[k]){
            flag[k<<1]=flag[k<<1|1]=flag[k];
            flag[k]=0;
        }
        if(sum[k]){
            sum[k<<1]+=sum[k];
            sum[k<<1|1]+=sum[k];
            sum[k]=0;
        }
    }
    //这个函数染色
    void modify1(int k,int left,int right,int l1,int r1,int x){
        if(l1<=left && r1>=right){
            flag[k]=x;
            return;
        }
        pushdown(k);
        int mid=left+right>>1;
        //注意这里不可以等于,因为维护区间[l1,l1]没有任何意义
        if(l1<mid) modify1(k<<1,left,mid,l1,r1,x);
        if(r1>mid) modify1(k<<1|1,mid,right,l1,r1,x);
    }
    //这个函数进行累加
    void modify2(int k,int left,int right,int l1,int r1){
        if(l1<=left && right<=r1){
            sum[k]++;
            return;
        }
        pushdown(k);
        int mid=left+right>>1;
        if(l1<mid) modify2(k<<1,left,mid,l1,r1);
        if(r1>mid) modify2(k<<1|1,mid,right,l1,r1);
    }
    //统计
    void query(int k,int left,int right){
        if(flag[k]){
            //因为直接维护坐标,所以两坐标直接相减
            res[flag[k]]+=(ll)sum[k]*(a[right]-a[left]);
            return;
        }
        if(left+1==right)//判断退出递归并不是通过判断(l==r)
            return;
        pushdown(k);
        int mid=left+right>>1;
        query(k<<1,left,mid);
        query(k<<1|1,mid,right);
    }   
    
    int main(){
        int n,m;
        while(scanf("%d%d",&n,&m)==2){
            a.clear();
            //build()=init()
            memset(sum,0,sizeof sum);
            memset(flag,0,sizeof flag);
            memset(res,0,sizeof res);
    
            for(int i=1;i<=n;i++){
                scanf("%d%d",&l[i],&r[i]);
                a.push_back(l[i]);
                a.push_back(r[i]);
            }
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].h);
                b[i].id=i;
                a.push_back(b[i].l);
                a.push_back(b[i].r);
            }
            sort(a.begin(), a.end());
            a.erase(unique(a.begin(),a.end()),a.end());
            int cnt=a.size();
            
            sort(b+1,b+1+m,cmp);
            for(int i=1;i<=m;i++){
                int pos1=lower_bound(a.begin(),a.end(),b[i].l)-a.begin();
                int pos2=lower_bound(a.begin(),a.end(),b[i].r)-a.begin();
                modify1(1,0,cnt-1,pos1,pos2,b[i].id);
            }
            for(int i=1;i<=n;i++){
                int pos1=lower_bound(a.begin(),a.end(),l[i])-a.begin();
                int pos2=lower_bound(a.begin(),a.end(),r[i])-a.begin();
                modify2(1,0,cnt-1,pos1,pos2);
            }
            query(1,0,cnt-1);
            for(int i=1;i<=m;i++)
                printf("%lld
    ",res[i]);
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    对字符串进行编码解码
    C#重新启动时,关闭较早的进程
    JS给HTML5页面<Select></Select>绑定选中项
    获取该项目路径下的文件路径
    IE浏览器从页面向后台Controller传中文值出现乱码问题
    委托
    win10激活命令
    判断窗口是否已经被打开
    JS之对象数组遍历?
    JS之arguments属性解读函数传参?
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9929694.html
Copyright © 2020-2023  润新知