【cdoj 1325】卿学姐与基本法 离散化+线段树

好吧,第一次写离散化的线段树,用的有点久,主要是因为网上有没有标程,所以自有自己一个人慢慢调,我也是心累,不过最后写出来了还是蛮开心的,啦啦啦

注意几点:

1.在离散化以后,各个点之间不再是连续的了,所以要加一个flag标记,查询这个节点为根的子树中有没有更改然后记录它的右子树中最左边的点和左子树中最右边的点,好减

2.每次更新sum的时候需要用到上面说的右子树中最左边的点和左子树中最右边的点,有点绕;

3.找到区间后直接返回sum,不必再减

4.在释放懒惰标记的时候,子树的flag标记也需要标记上

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100020
#define ls u<<1,l,mid
#define rs u<<1|1,mid+1,r
using namespace std;
int n,q,cur[maxn*2],cnt;
struct node{
    int l,r,sum,add,flag,ll,lr,rl,rr;
}nod[maxn*4];
struct edge{
    int t,l,r;
}e[maxn*2];
bool cmp(int a,int b){return a<b;}

void push_up(int u){
    nod[u].sum=nod[u<<1].sum+nod[u<<1|1].sum;
    nod[u].ll=nod[u<<1].ll;nod[u].lr=nod[u<<1].rr;
    nod[u].rl=nod[u<<1|1].ll;nod[u].rr=nod[u<<1|1].rr;
    if(nod[u].flag)nod[u].sum+=nod[u<<1|1].ll-nod[u<<1].rr-1;
}

void push_down(int u){
    if(!nod[u].add)return;
    nod[u<<1].sum=nod[u<<1].r-nod[u<<1].l+1;
    nod[u<<1|1].sum=nod[u<<1|1].r-nod[u<<1|1].l+1;
    nod[u<<1].add=nod[u].add;
    nod[u<<1|1].add=nod[u].add;
    nod[u<<1].flag =nod[u<<1|1].flag =1;
    nod[u].add=0;
}

void build(int u,int l,int r){
    nod[u].l=cur[l];nod[u].r=cur[r];
    if(l==r){
        nod[u].ll=nod[u].rr=nod[u].lr=nod[u].rl=cur[l];
        nod[u].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    build(ls);
    build(rs);
    push_up(u);
}

void update(int u,int l,int r,int x,int y,int add){
    if(nod[u].l==x&&nod[u].r==y){
        nod[u].flag=1;
        nod[u].add=add;
        nod[u].sum=nod[u].r-nod[u].l+1;
        return;
    }
    push_down(u);
    int mid=(l+r)>>1;
    if(x>cur[mid])update(rs,x,y,add);
    else if(y<=cur[mid])update(ls,x,y,add);
    else {
        nod[u].flag=1;
        update(ls,x,cur[mid],add);
        update(rs,cur[mid+1],y,add);
    }
    push_up(u);
}

int query(int u,int l,int r,int x,int y){
    if(x==nod[u].l&&y==nod[u].r ){
        int ans=0;
        if(!nod[u].flag )ans+=nod[u].rl-nod[u].lr -1;
        return nod[u].r-nod[u].l+1-nod[u].sum;
    }
    push_down(u);
    int mid=(l+r)>>1;
    if(x>cur[mid])return query(rs,x,y);
    else if(y<=cur[mid])return query(ls,x,y);
    else{
        int ans=0;
        if(!nod[u].flag)ans+=nod[u].rl-nod[u].lr -1;
        return query(ls,x,cur[mid])+query(rs,cur[mid+1],y)+ans;
    }
}
 
int main(){
    scanf("%d%d",&n,&q);
    int a,b,c;
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&a,&b,&c);
        cur[++cnt]=b;
        cur[++cnt]=c;
        e[i].t=a;e[i].l=b;e[i].r=c;
        
    }   
    
    sort(cur+1,cur+1+cnt,cmp);
    cnt=unique(cur+1,cur+1+cnt)-cur-1;
    build(1,1,cnt);
    for(int i=1;i<=q;i++){
        if(e[i].t==1)update(1,1,cnt,e[i].l,e[i].r ,1);
        else printf("%d\n",query(1,1,cnt,e[i].l ,e[i].r ));
        //cout<<endl;
    }
    return 0;
}       



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值