Help with Intervals 线段树区间更新

Posted qq2210446939

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Help with Intervals 线段树区间更新相关的知识,希望对你有一定的参考价值。

  题意:给你一个初始为空的集合,对其进行5种操作若干遍,输出最终的集合。

 

  设S为一开始的集合,则: U  T 表示 S=S∪T

            I   T 表示 S=S∩T

              D  T 表示 S=S-T

              C  T 表示 S=T-S

              S  T 表示 S=S异或T

 

  思路:用线段树模拟区间操作,叶子结点为1代表区间存在,0代表不存在,因为区间有开区间和闭区间两种,单单用叶子结点模拟自然数实现不了开区间,所以我们对坐标系×2扩大,原来的闭区间整数点对应扩大后的偶数点,1 2 3 4 5 变成2 4 6 8 10,原来的开区间例如(2,3】,扩大后变成(4,6】,再将开区间的端点相中心靠拢(4,6】->【5,6】由于新坐标系的偶数对应原坐标系,则新坐标系的奇数就可以用来实现开区间,然后区间更新实现操作即可。

  具体做法:设区间T为【L,R】,U T就是将T区间全更新为1。I T就是将【0,L-1】和【R+1,maxn】更新为0,因为求交集,则T区间以外的区间就不能存在,T区间之内的任由原来的S怎么地,就实现了交集。D T 就是将区间T变为0。对于C T,则是将T区间翻转,将T区间外变成0,因为是T-S,则T区间外一定是0,T区间内,S内就变为0,外就是1,就是翻转嘛。对于异或,S有的T没有的,T有的S没有的,这样的目标区间只需要将T区间翻转即可,T区间外的自然不影响,则S有的T没有的得到了保留,对于T区间内,有S的地方变为了0,没S的地方变成了1,所以即可达到操作!

 

AC代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=2e5+10;
int col[maxn<<2];

void pushdown(int rt){
    if(col[rt]==2){
        col[rt<<1]=1-col[rt<<1];
        col[rt<<1|1]=1-col[rt<<1|1];
        col[rt]=-1;
    }
    if(col[rt]!=-1){
        col[rt<<1]=col[rt<<1|1]=col[rt];
        col[rt]=-1;
    }
}
void check(){
    cout<<"**********************
";
    for(int i=1;i<=50;i++)
        cout<<col[i]<<" ";
    cout<<"
********************
";
}

void updata(int L,int R,int val,int l,int r,int rt){
    if(L<=l&&r<=R){
        if(val==2) col[rt]=1-col[rt];
        else col[rt]=val;
        return;
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m)
        updata(L,R,val,l,m,rt<<1);
    if(R>m)
        updata(L,R,val,m+1,r,rt<<1|1);
}

int search(int pos,int l,int r,int rt){
    if(l==r){
        return col[rt];
    }
    int m=l+r>>1;
    pushdown(rt);
    if(pos<=m)
        return search(pos,l,m,rt<<1);
    else
        return search(pos,m+1,r,rt<<1|1);
}



int main()
{
     int a,b;
    char s,sl,sr,sm;
    memset(col,0,sizeof(col));
    while(~scanf(" %c %c%d %c%d %c",&s,&sl,&a,&sm,&b,&sr)){
        a<<=1;
        b<<=1;
        if(sl==() a++;
        if(sr==)) b--;
        if(s==U) updata(a,b,1,0,maxn,1);
        if(s==I){
               if(a>0)
                updata(0,a-1,0,0,maxn,1);
            updata(b+1,maxn,0,0,maxn,1);
        }
        if(s==D)  updata(a,b,0,0,maxn,1);
        if(s==C){
            updata(a,b,2,0,maxn,1);
            if(a>0)
                updata(0,a-1,0,0,maxn,1);
            updata(b+1,maxn,0,0,maxn,1);
        }
        if(s==S){
            updata(a,b,2,0,maxn,1);
          }
    }
    int flag=0,k=0;
    for(int i=0;i<maxn;i++){
        int now=search(i,0,maxn,1);
        if(k==0&&now==1){
            if(i%2==0)
                printf("[%d,",i/2);
            else
                printf("(%d,",i/2);
            k=1;
            flag=1;
        }
        if(k==1&&now==0){
            int index=i-1;//最后一个1的下标
            if(index%2==0)
                printf("%d] ",(index+1)/2);
            else
                printf("%d) ",(index+1)/2);//如果是奇数,则表示的是index+1这个右端点的开区间
                //若index=5 则原区间是...,3)
            k=0;
        }
    }
    if(flag==0) printf("empty set
");
    return 0;
}
/*
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
*/

以上是关于Help with Intervals 线段树区间更新的主要内容,如果未能解决你的问题,请参考以下文章

Help with Intervals 线段树区间更新

模板线段树

POJ1375 Intervals(直线与圆切线线段合并)

POJ 3680 Intervals

ZOJ 3953:Intervals(优先队列+思维)

POJ 1201 Intervals