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