[BZOJ3226][SDOI2008]校门外的区间(线段树)

本文介绍了一种基于线段树的数据结构实现方法,用于高效处理区间查询与更新操作。文章详细阐述了如何通过标记传递等技巧来优化区间翻转、区间赋值等功能,并提供了完整的C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

fBAgGjwvfrKU

题目:

我是超链接

题解:

如何处理开闭区间?开两倍的节点,一部分代表端点,一部分代表区间
然而一开始愚蠢的up选择1-base为区间,base+1-Max为端点,然后就开始无穷无尽的调试,最后还没法输出
没办法了,那就让端点和区间挨着吧,一个端点一个区间。。。
这些操作也很明了了
And 两侧变成0
Or 区间全1
已有-新读 区间全0
新读-已有 两侧全0,区间内取反
异或 区间内取反

还有一个问题,先处理delta还是先all呢?我们发现当delta在下面的时候,不管下面打不打完标记,只要上面有一个all就跟delta没啥关系了,当all在下面的时候,我们必须先处理完下面的然后再让delta取反。由此观之,我们要先处理all。其次多pushdown几次就好了

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Max=65536*2+1;
int delta[Max*4],w[Max*4],all[Max*4];
void pushdown(int now,int l,int r)
{
    if(l==r)
    {
        if(all[now]!=-1) w[now]=all[now];
        w[now]^=delta[now];
        all[now]=-1;delta[now]=0;
        return;
    }
    if(all[now]!=-1)
    {
        all[now<<1]=all[now<<1|1]=all[now];
        delta[now<<1]=delta[now<<1|1]=0; /////
    }
    delta[now<<1]^=delta[now];delta[now<<1|1]^=delta[now];
    all[now]=-1;delta[now]=0;
}
void change(int now,int l,int r,int lrange,int rrange,int v)
{
    if (lrange>rrange) return;
    pushdown(now,l,r);
    if (lrange<=l && rrange>=r) {all[now]=v;return;}
    int mid=(l+r)>>1;pushdown(now,l,r);
    if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,v);
    if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,v);
    pushdown(now,l,r);
}
void qufan(int now,int l,int r,int lrange,int rrange)
{
    if (lrange>rrange) return;
    pushdown(now,l,r);
    if (lrange<=l && rrange>=r) {delta[now]^=1; return;}
    int mid=(l+r)>>1;pushdown(now,l,r);
    if (lrange<=mid) qufan(now<<1,l,mid,lrange,rrange);
    if (rrange>mid) qufan(now<<1|1,mid+1,r,lrange,rrange);
    pushdown(now,l,r);
}
int qurry(int now,int l,int r,int x)
{
    pushdown(now,l,r);
    if (l==r) return w[now];
    int mid=(l+r)>>1;
    if (x<=mid) return qurry(now<<1,l,mid,x);
    else return qurry(now<<1|1,mid+1,r,x);
}
int main()
{
    char st[5],s[15];
    memset(all,-1,sizeof(all));
    while (scanf("%s",st)!=EOF)
    {
        scanf("%s",s+1);
        int len=strlen(s+1),l,r,x=0,z=0,y=0;
        for (int j=1;j<=len;j++)
        {
            if (j==1) {if (s[j]=='(') z=1; continue;}
            if (j==len) {if (s[j]==')') y=-1; continue;}
            if (s[j]==',') {l=x;x=0;continue;}
            x=x*10+s[j]-'0';
        }
        r=x;
        l=l*2+1+z;//0
        r=r*2+1+y;//0
        switch (st[0])
        {
            case 'U':change(1,1,Max,l,r,1);break;
            case 'I':change(1,1,Max,1,l-1,0);change(1,1,Max,r+1,Max,0);break;
            case 'D':change(1,1,Max,l,r,0);break;
            case 'C':change(1,1,Max,1,l-1,0);change(1,1,Max,r+1,Max,0);qufan(1,1,Max,l,r);break;
            case 'S':qufan(1,1,Max,l,r);break;
        }
    }   
    int be=0,la=0;bool fff=0,yx=0;
    for (int i=1;i<=Max;i++)
    {
        if (qurry(1,1,Max,i))
        {
            if (yx==0) be=i,yx=1;
            fff=1;
            la=i;
        }
        else if (yx)
        {
            if (be%2) printf("[");else printf("(");
            printf("%d,%d",(be-1)/2,la/2);
            if (la%2) printf("] ");else printf(") ");
            yx=0;
        }
    }
    if (!fff) printf("empty set"); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值