bjfu.oj-1470 poj-2777
来源:互联网 发布:如何做好淘宝客推广 编辑:程序博客网 时间:2024/06/06 02:42
跨过了线段树,然后我居然不会这个按位计算,窝真是水的一比,弱得不行。
题意大致是:一段路,每次涂色一段一段涂(成段更新),询问某一段共有多少种颜色(成段询问)
一看就是比较水的线段树,用lazy就可以优化的东西,然后我就一直在想如何更新某一段一共有多少种颜色呢??? 想啊想啊想啊,然后发现我用什么方法都会在极限的情况下可能超时!
然后就sb了,后来学习了一下按位计算,恍然大悟:因为最多也只可能有30种颜色,可以用一个int类型的数字保存就行了(2^32 可以满足了),下面解释一下按位计算吧。
每一个数字都可以化作二进制数,30种颜色我们用一个2^30的int型数表示即可,然后第i种颜色,我们用从右往左数过去的第i位0->1 ,即2^(i-1),然后父亲节点的color值 就= 左子树col | 右子树 col
这样我们在查询某一个区间的时候我们就可以直接选取这一个区间的col 值,然后进行按位处理,处理数字为1的位有多少个就行了
#include<iostream>#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>#include<stdlib.h>#include<queue>#include<stack>#include<map>#include<vector>#define mem(a) memset(a,0,sizeof(a))#define pfn printf("\n")#define sf scanf#define pf printf#define fr(i,n) for(int i=0;i<n;i++)#define INF 0x7fffffff //INT_MAX#define inf 0x3f3f3f3f //const double PI = acos(-1.0);const double e = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }using namespace std;#define lson l , mid , rt << 1#define rson mid + 1 , r , rt << 1 | 1const int N=100010;#define Lson (rt<<1)#define Rson (rt<<1|1)struct Tree{ int l,r; int col; // 用一个32位的int型,已经够30种颜色了 bool lazy; //懒惰标记下 这里的意义是:若被标记为1,表示下面的子树都被画成了同一种颜色}tree[N<<2];void Pushup(int rt){ //向上更新 tree[rt].col=tree[Lson].col | tree[Rson].col; //按位或,可以不重复的包括子树的颜色}void build(int L,int R,int rt){ tree[rt].l=L; tree[rt].r=R; tree[rt].col=1; // 开始时都为涂有颜色1 tree[rt].lazy=1; //一开始把lazy设置为1,表示这一段全部都被设置为同一种颜色 if(tree[rt].l==tree[rt].r) return ; int mid=(L+R)>>1; build(L,mid,Lson); build(mid+1,R,Rson);}void Pushdown(int rt){ //向下更新 tree[Lson].col=tree[rt].col; tree[Lson].lazy=1; tree[Rson].col=tree[rt].col; tree[Rson].lazy=1; tree[rt].lazy=0; //对lazy 的一顿操作}void update(int val,int L,int R,int rt){ if(L<=tree[rt].l && R>=tree[rt].r){ tree[rt].col=val; tree[rt].lazy=1; // return ; } if(tree[rt].col==val) //如果相同那么就不需要再更新下去 return ; if(tree[rt].lazy) // Pushdown(rt); int mid=(tree[rt].l+tree[rt].r)>>1; if(R<=mid) update(val,L,R,Lson); else if(L>=mid+1) update(val,L,R,Rson); else{ update(val,L,mid,Lson); update(val,mid+1,R,Rson); } Pushup(rt); // 最后更新下父亲节点的颜色}int sum;void query(int L,int R,int rt){ if(L<=tree[rt].l && R>=tree[rt].r){ sum |= tree[rt].col; return ; } if(tree[rt].lazy){ // 这个区间全部为1种颜色,就没有继续分割区间的必要了 sum |= tree[rt].col; // 颜色种类相加的位运算代码 return; } int mid=(tree[rt].l+tree[rt].r)>>1; if(R<=mid) query(L,R,Lson); else if(L>=mid+1) query(L,R,Rson); else{ query(L,mid,Lson); query(mid+1,R,Rson); }}int solve(){ int ans=0; while(sum){ if(sum&1) //按位与 一共30位,若是这一位是1,那么表示这位有颜色。 ans++; sum>>=1; //n的各个二进制位顺序右移1位,最高位补二进制0 } return ans;}void swap(int &a,int &b){ int tmp=a;a=b;b=tmp;}int main(){ //freopen("1.txt","r",stdin); int n,t,m; while(~scanf("%d%d%d",&n,&t,&m)){ build(1,n,1); char str[3]; int a,b,c; while(m--){ scanf("%s",str); if(str[0]=='C'){ scanf("%d%d%d",&a,&b,&c); update(1<<(c-1),a,b,1); // int型的右起第c位变为1,即2的c-1次方。 } else{ scanf("%d%d",&a,&b); sum=0; query(a,b,1); printf("%d\n",solve()); } } } return 0;}
0 0
- bjfu.oj-1470 poj-2777
- bjfu oj 1011 将浮点数转换为分数相除的形式
- bjfu oj 1011 将浮点数转换为分数相除的形式
- bjfu 1009
- bjfu 1008
- BJFU 1406
- bjfu 1008
- bjfu 1006 bool 排序
- 最大公约数 bjfu 1050 水题
- BJFU-ACM-1009 抽奖
- BJFU-ACM-1004 Sudoku
- BJFU 1271 惊讶N
- BJFU 1398 蚂蚁下落
- poj 北大 oj 1840 Eqs
- bjfu---1196fudq and Digital
- bjfu---fudq and IME Again
- BJFU 1002——九九乘法表
- BJFU 1004——Sudoku
- 实现带样式的表单验证:用户名、密码验证
- java多线程的一个案例
- 转载一篇对php变量名的问题,很有意思,之前没注意过
- IOS 页面之间的跳转以及传值
- GDB调试器
- bjfu.oj-1470 poj-2777
- 读取并修改元素的属性:实现多标签页效果
- php redis 常用操作
- [算法]欧几里得算法——求解最大公因数
- hdu4021——N数码问题及其扩展
- make
- 安卓开发:Volley加载图片
- Log4j每天、每小时、每分钟定时生成日志文件
- EffectiveJava-8所有类都通用的方法-equals()、hashCode()、toString()