zoukankan      html  css  js  c++  java
  • 【日记】12.7

    12.7日记

    线段树

    1. POJ3667:区间修改+询问最靠左的长度为x的连续区间。

    思路和上个题差不多,只不过这里是区间修改,所以只能用线段树了。这里注意如果是直接修改值的话,lazy标记的初始值必须是-1,因为可以改成0。出了点小错误,以后写代码还是要仔细。

    #include<cstdio>
    #include<algorithm>
    #define mid (l+r)/2
    using namespace std;
    const int M=5e4+20;
    int lm[4*M],rm[4*M],mm[4*M],col[4*M],lazy[4*M];
    inline void pushup(int id,int l,int r){
        if (col[id*2]==1)
            lm[id]=lm[id*2]+lm[id*2+1];
        else
            lm[id]=lm[id*2];
        if (col[id*2+1]==1)
            rm[id]=rm[id*2+1]+rm[id*2];
        else
            rm[id]=rm[id*2+1];
        mm[id]=max(max(mm[id*2],mm[id*2+1]),rm[id*2]+lm[id*2+1]);
        if (mm[id]==0)
            col[id]=0;
        else if (mm[id]==r-l+1)
            col[id]=1;
        else
            col[id]=-1;
    }
    inline void pushdown(int id,int l,int r){
        if (lazy[id]==0)
            lazy[id*2]=lazy[id*2+1]=lm[id*2]=lm[id*2+1]=rm[id*2]=rm[id*2+1]=mm[id*2]=mm[id*2+1]=col[id*2]=col[id*2+1]=0;
        else if (lazy[id]==1)
            lazy[id*2]=lazy[id*2+1]=1,
            lm[id*2]=rm[id*2]=mm[id*2]=mid-l+1,
            lm[id*2+1]=rm[id*2+1]=mm[id*2+1]=r-mid,
            col[id*2]=col[id*2+1]=1;
        lazy[id]=-1;
    }
    void build(int id,int l,int r){
        col[id]=1,lm[id]=rm[id]=mm[id]=r-l+1,lazy[id]=-1;
        if (l==r)
            return;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        pushup(id,l,r);
    }
    void operate(int id,int l,int r,int ql,int qr,int x){
        if (ql<=l&&r<=qr){
            if (x)
                lm[id]=rm[id]=mm[id]=r-l+1,
                col[id]=lazy[id]=1;
            else
                lm[id]=rm[id]=mm[id]=col[id]=lazy[id]=0;
            return;
        }
        pushdown(id,l,r);
        if(ql<=mid)
            operate(id*2,l,mid,ql,qr,x);
        if (mid<qr)
            operate(id*2+1,mid+1,r,ql,qr,x);
        pushup(id,l,r);
    }
    int query(int id,int l,int r,int x){//第一个长度至少为x的区间的左端点
        pushdown(id,l,r);
        if (mm[id*2]>=x)
            return query(id*2,l,mid,x);
        if (rm[id*2]+lm[id*2+1]>=x)
            return mid-rm[id*2]+1;
        if (mm[id*2+1]>=x)
            return query(id*2+1,mid+1,r,x);
        return 0;
    }
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            build(1,1,n);
            for(int i=1;i<=m;++i){
                int op;
                scanf("%d",&op);
                if (op==1){
                    int x;
                    scanf("%d",&x);
                    int ca=query(1,1,n,x);
                    if (ca)
                        operate(1,1,n,ca,ca+x-1,0);
                    printf("%d
    ",ca);
                }
                else{
                    int x,y;
                    scanf("%d%d",&x,&y);
                    operate(1,1,n,x,x+y-1,1);
                }
            }
        }
        return 0;
    }
    
    1. HDU3308:单点修改+区间查询最长连续上升子序列

    思路一样,只不过这里查询的时候,需要对两个区间进行合并操作,有些细节还是要注意的。这样的话写成struct是最方便的,于是把代码又重构了一遍……其实也就是搜索替换一下就可以了。

    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    const int M=1e5+20;
    int a[M];
    struct Seg{
        int lf,rt,lm,rm,mm,col,len;
        Seg(int a=0,int b=0,int c=0,int d=0,int e=0,int f=0,int g=0):lf(a),rt(b),lm(c),rm(d),mm(e),col(f),len(g){}
    }v[4*M];
    inline Seg merge(Seg lef,Seg rit){
        Seg ans;
        ans.lf=lef.lf,ans.rt=rit.rt;
        ans.len=lef.len+rit.len;
        if (lef.col==1&&lef.rt<rit.lf)
            ans.lm=lef.lm+rit.lm;
        else
            ans.lm=lef.lm;
        if (rit.col==1&&lef.rt<rit.lf)
            ans.rm=rit.rm+lef.rm;
        else
            ans.rm=rit.rm;
        ans.mm=max(lef.mm,rit.mm);
        if (lef.rt<rit.lf)
            ans.mm=max(ans.mm,lef.rm+rit.lm);
        if (ans.mm==0)
            ans.col=0;
        else if (ans.mm==ans.len)
            ans.col=1;
        else
            ans.col=-1;
        return ans;
    }
    void build(int id,int l,int r){
        if (l==r){
            v[id].lf=v[id].rt=a[l],
            v[id].col=v[id].lm=v[id].rm=v[id].mm=v[id].len=1;
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        v[id]=merge(v[id*2],v[id*2+1]);
    }
    void operate(int id,int l,int r,int pos,int x){
        if (l==r){
            v[id].lf=v[id].rt=x,
            v[id].lm=v[id].rm=v[id].mm=v[id].col=1;
            return;
        }
        if(pos<=mid)
            operate(id*2,l,mid,pos,x);
        else
            operate(id*2+1,mid+1,r,pos,x);
        v[id]=merge(v[id*2],v[id*2+1]);
    }
    Seg query(int id,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)
            return v[id];
        Seg lef,rit;
        if(ql<=mid)
            lef=query(id*2,l,mid,ql,qr);
        if (mid<qr)
            rit=query(id*2+1,mid+1,r,ql,qr);
        if (lef.mm==0)
            return rit;
        if (rit.mm==0)
            return lef;
        return merge(lef,rit);
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int z=1;z<=T;++z){
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i)
                scanf("%d",&a[i]);
            build(1,1,n);
            for(int i=1;i<=m;++i){
                char s[2];
                int a,b;
                scanf("%s%d%d",s,&a,&b);
                if (s[0]=='Q')
                    printf("%d
    ",query(1,1,n,a+1,b+1).mm);
                else
                    operate(1,1,n,a+1,b);
            }
        }
        return 0;
    }
    

    CDQ

    1. HDU1541:二维偏序。

    思路:和之前一样。这里求的是(a_2leq a)(b_2leq b)的数量,对每个数量输出满足条件的个数。排序必须要第一维为第一关键字,第二维为第二关键字!不然后面数顺序对会出错!再用CDQ求顺序对个数。对于第i个数,以他为结尾的顺序对+逆序对=i-1,所以可以直接求逆序对个数,记录每个数对应逆序对的个数,再剪一下即可。这里用了结构体,所以一定是先修改答案,再存入ca数组!!!

    #include<bits/stdc++.h>
    using namespace std;
    #define mid (l+r)/2
    const int M=1e5+20;
    int res[M];
    struct Star{
        int x,y,num,ans;
        Star(int a=0,int b=0,int c=0,int d=0):x(a),y(b),num(c),ans(d){}
    }star[M],ca[M];
    bool cmp(const Star &a,const Star &b){
        return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    void CDQ(int l,int r){
        if (l==r)
            return;
        CDQ(l,mid),CDQ(mid+1,r);
        int i=l,j=mid+1,k=l;
        while (i<=mid&&j<=r)
            if (star[i].y<=star[j].y)
                ca[k++]=star[i++];
            else
                star[j].ans+=mid-i+1,ca[k++]=star[j],++j;
        while (i<=mid)
            ca[k++]=star[i++];
        while (j<=r)
            ca[k++]=star[j++];
        for (int i=l;i<=r;++i)
            star[i]=ca[i];
    }
    int main(){
        int n;
        while(~scanf("%d",&n)){
            for (int i=1;i<=n;++i)
                scanf("%d%d",&star[i].x,&star[i].y),star[i].ans=0,res[i-1]=0;
            sort(star+1,star+n+1,cmp);
            for(int i=1;i<=n;++i)
                star[i].num=i;
            CDQ(1,n);
    		for(int i=1;i<=n;++i)
                ++res[star[i].num-1-star[i].ans];
            for(int i=0;i<=n-1;++i)
                printf("%d
    ",res[i]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    hdu 1532(最大流)
    星沉月朗
    uva 818 (位运算 + 判环)
    SQL变量、Substring、charindex、case函数、去除重复
    C# Tostring格式
    asp.net导出word(word2007)
    asp.net生成缩略图
    正则表达式语法
    解压缩
    文件复制
  • 原文地址:https://www.cnblogs.com/diorvh/p/12008848.html
Copyright © 2011-2022 走看看