poj 3225 线段树+位运算

略复杂的一道题,首先要处理开闭区间问题,扩大两倍即可,注意输入最后要\n,初始化不能随便memset

采用线段树,对线段区间进行0,1标记表示该区间是否包含在s内
U T S ← S ∪ T 即将[l,r]标记为1
I T S ← S ∩ T 即将-oo~l和r~+oo标记为0,因为是并集,所以并集后的集合s一定在[l,r]内,则在l,r内的集合被标记是什么状态就是什么状态(表示是否属于s),[l,r]外的集合不属于s所以标记为0
D T S ← S - T  即将[l,r]标记为0,则在[l,r]内被s包含的集合也会标记为0表示不再属于s
C T S ← T - S  即先将-oo~l,r~+oo标记为0,这部分不属于[l,r]则一定不属于s,然后将[l,r]的标记0/1互换,因为属于s的不再属于s,不属于s的将属于s
S T S ← S ⊕ T  即属于s的不变,[l,r]中不属于s的(区间)0标记为1,属于s的(区间)1标记为0,所以[l,r]的标记0/1互换

最后对区间l,r标记时标记将l*2,r*2标记,如果是闭区间则对l*2+1,或r*2-1进行标记,则输出的时候只需判断奇偶就能判断开闭区间
是否覆盖0,1是否转换0,1的0,1转换都可以用异或去转换
Sample Input
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
Sample Output
(2,3)

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<queue>
  7 #define lson l,m,rt<<1
  8 #define rson m+1,r,rt<<1|1
  9 using namespace std;
 10 const int maxn=131072;
 11 int tot=0;
 12 int n,m,t;
 13 int Xor[maxn<<2],cov[maxn<<2];   //异或标记,覆盖标记
 14 int hash[maxn<<2];
 15 void XXor(int rt)
 16 {
 17     if(cov[rt]!=-1) cov[rt]^=1;     //说明该区域有值存在
 18     else Xor[rt]^=1;
 19 }
 20 void pushdown(int rt)
 21 {
 22     if(cov[rt]!=-1)
 23     {
 24         cov[rt<<1]=cov[rt<<1|1]=cov[rt];
 25         Xor[rt<<1]=Xor[rt<<1|1]=0;
 26         cov[rt]=-1;
 27     }
 28     if(Xor[rt])
 29     {
 30         XXor(rt<<1);
 31         XXor(rt<<1|1);
 32         Xor[rt]=0;
 33     }
 34 }
 35 void update(char op,int L,int R,int l,int r,int rt)
 36 {
 37     if(l>=L&&r<=R)
 38     {
 39
 40         if(op==‘U‘) cov[rt]=1,Xor[rt]=0;
 41         else if(op==‘D‘)    cov[rt]=Xor[rt]=0;
 42         else if(op==‘C‘||op==‘S‘)   XXor(rt);
 43         return;
 44     }
 45     pushdown(rt);
 46     int m=(l+r)>>1;
 47     if(L<=m) update(op,L,R,lson);
 48     else if(op==‘I‘||op==‘C‘)   cov[rt<<1]=Xor[rt<<1]=0;
 49     if(m<R) update(op,L,R,rson);
 50     else if(op==‘I‘||op==‘C‘)   cov[rt<<1|1]=Xor[rt<<1|1]=0;
 51 }
 52 void query(int l,int r,int rt)
 53 {
 54     if(cov[rt]==1)
 55     {
 56         for(int i=l;i<=r;i++)   hash[i]=1;
 57         return;
 58     }
 59     else if(cov[rt]==0) return;
 60     if(l==r)    return;
 61     pushdown(rt);
 62     int m=(r+l)>>1;
 63     query(lson);
 64     query(rson);
 65 }
 66 int main()
 67 {
 68     int i,j,k;
 69     //freopen("1.in","r",stdin);
 70     char l,r,op;
 71     int a,b;
 72     while(scanf("%c %c%d,%d%c\n",&op,&l,&a,&b,&r)!=EOF)
 73     {
 74         a<<=1,b<<=1;    //区间扩大一倍,解决开闭区间问题
 75         //printf("%d %d\n",a,b);
 76         if(l==‘(‘)  a++;
 77         if(r==‘)‘)  b--;
 78         if(a>b)         //说明a和b的值相等
 79         {
 80             if(op==‘C‘||op==‘I‘)    cov[1]=Xor[1]=0,printf("");    //整个区间为0
 81         }
 82         else    update(op,a,b,0,maxn,1);
 83     }
 84     k=0;
 85     query(0,maxn,1);    //此时区间内的有效区域值为1
 86     int s=-1,e;    //判断左右区间位置
 87
 88     for(i=0;i<=maxn;i++)
 89     {
 90         if(hash[i]) //该区域被覆盖
 91         {
 92             if(s==-1)   s=i;
 93             e=i;
 94         }
 95         else
 96         {
 97             if(s!=-1)    //说明存在一个完整区间
 98             {
 99                 if(k++) printf(" ");
100                 printf("%c%d,%d%c",s&1?‘(‘:‘[‘,s>>1,(e+1)>>1,e&1?‘)‘:‘]‘);    //&运算用来判断奇偶,偶数的话二进制末位为0,and1得0,说明为闭区间
101                 s=-1;
102             }
103         }
104     }
105     if(k==0)    printf("empty set");
106     puts("");
107     return 0;
108 }
时间: 2024-09-30 00:22:54

poj 3225 线段树+位运算的相关文章

POJ 2777 Count Color (线段树+位运算)

题意很简单了,对一个区间有两种操作: 1. "C A B C" Color the board from segment A to segment B with color C. //A~B涂上颜色C 2. "P A B" Output the number of different colors painted between segment A and segment B (including). //输出A~B间颜色的种类数 题目链接:http://poj.o

hdu5023A Corrupt Mayor&#39;s Performance Art(线段树+位运算)

题目链接: huangjing 题意: 有一快板子,然后这个板子被分为从1到n小块,然后给了m个操作,p a b c,是将板子a,b涂成c种颜色,q a b是询问这a到b快板子中有多少种颜色.. 思路: 这个是典型的区间更新,然后涂颜色涉及到位运算,将每一种颜色表示数的各个位,那么这个问题就简单了,,但是我还是一直wa到死,因为我开了一个fbi数组保存结果,结果我把fbi数组开到maxn大小,结果又脑残的对每次询问都进行初始化memset,结果就超时了,还以为自己线段树写挫了..下次开数组都要小

POJ 2777 Count Color(线段树+位运算)

题目链接:http://poj.org/problem?id=2777 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a

POJ 3225(线段树)

POJ 3225 题 意 : 区 间 操 作 , 交 , 并 , 补 等 思 路 : 我 们 一 个 一 个 操 作 来 分 析 :( 用 0 和 1 表 示 是 否 包 含 区 间 , - 1 表 示 该 区 间 内 既 有 包 含 又有 不 包 含 ) U : 把 区 间 [l,r ] 覆 盖 成 1 I: 把 [ - ∞ ,l) ( r, ∞ ] 覆 盖 成 0 D : 把 区 间 [l,r ] 覆 盖 成 0 C : 把 [ - ∞ ,l) ( r, ∞ ] 覆 盖 成 0 , 且 [l

Codeforces Round #590 (Div. 3) D. Distinct Characters Queries(线段树, 位运算)

链接: https://codeforces.com/contest/1234/problem/D 题意: You are given a string s consisting of lowercase Latin letters and q queries for this string. Recall that the substring s[l;r] of the string s is the string slsl+1-sr. For example, the substrings

POJ 3225 (线段树 区间更新) Help with Intervals

这道题搞了好久,其实坑点挺多.. 网上找了许多题解,发现思路其实都差不多,所以就不在重复了. 推荐一篇比较好的题解,请戳这. 另外,如果因为可能要更新多次,但最终查询只需要一次,所以没有写pushup函数,仅有一个pushdown. 1 #include <cstdio> 2 3 const int maxn = 131072; 4 //const int maxn = 10; 5 int qL, qR, op; 6 int setv[maxn << 2], xorv[maxn &

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9

poj 2777 线段树的区间更新

Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Chosen Problem Solving and Program design as an optional course, you are required to solve al

转载::POJ 2991 线段树+计算几何(有c++结构体操作)

POJ 2991 线段树+计算几何 (2011-02-27 21:13:44) 转载▼ 标签: 杂谈 分类: OI 话说这一题真的是很恶心很恶心,不过确实改变了我对线段树的一些看法,算是很经典的题目. 题意:有一个吊车由很多个不同长度的线段组成,一开始是一条长直线起点在(0,0),尾节点在(0,sum[n]),每条线段之间的夹角的初始值是180度.然后有一些操作a. b将第a条线段和a+1之间的夹角变成b度,经过每一次操作都要求出尾节点的坐标. 首先要用到一个计算几何的知识(没学过..请教而来)