Diorvh

导航

【日记】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\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<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\n",query(1,1,n,a+1,b+1).mm);
            else
                operate(1,1,n,a+1,b);
        }
    }
    return 0;
}

CDQ

  1. HDU1541:二维偏序。

思路:和之前一样。这里求的是\(a_2\leq a\)\(b_2\leq 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\n",res[i]);
    }
    return 0;
}

posted on 2019-12-09 01:50  diorvh  阅读(153)  评论(0编辑  收藏  举报