【日记】12.7

12.7日记

线段树

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

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

#include
#include
#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=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\n",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
#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

CDQ

  1. HDU1541:二维偏序。

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

#include
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

你可能感兴趣的:(【日记】12.7)