Luogu P1558 色板游戏

  (此题与POJ2777重题)

  为了加深对线段树的记忆,然后开始搞这道题。

  TM的WA了一下午就是发现x可能大于y(然而题目里说的还很清楚,我TM没看见)

  这道题只需要在线段树的板子上改一些地方就可以了:

  1.存储时不是存储颜色,而是将它状压成一个整数(如序号为3的颜色存为1<<3=8)

  2.回溯时不是取和相加,而是直接按位或(|),原理等下讲

  3.最后的查询完毕的值统计一下二进制下有多少个1就是ans

  最后讲一下为什么要| 

  假如3种颜色 2,3,3,在树上记为4,8,8,它们对应的二进制就是(100,1000,1000)

  有没有发现,每个数的二进制下都只有一位上有1,而且不同颜色的数1的位置不同

  因此在|的时候,只要这一位上有1,那么就一定有这种颜色

  线段树就是板子,套一套就好了

  CODE

#include<cstdio>
#include<iostream>
using namespace std;
const int N=100005;
int tree[N*4],add[N*4],l,t,o,x,y,z;
char ch;
inline void read(int &x)
{
    x=0; char ch=getchar(); int flag=1;
    while (ch<'0'||ch>'9') { if (ch=='-') flag=-1; ch=getchar(); }
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=flag;
}
inline void write(int x)
{
    if (x/10) write(x/10);
    putchar(x%10+'0');
}
inline void up(int root)
{
    tree[root]=tree[root*2]|tree[root*2+1];
}
inline void down(int root)
{
    if (add[root])
    {
        tree[root*2]=add[root];
        tree[root*2+1]=add[root];
        add[root*2]=add[root];
        add[root*2+1]=add[root];
        add[root]=0;
    }
}
inline void build(int root,int l,int r)
{
    if (l==r)
    {
        tree[root]=2;
        return;
    }
    int mid=l+r>>1;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
    up(root);
}
inline void change(int root,int l,int r,int beg,int end,int col)
{
    if (l>=beg&&r<=end)
    {
        tree[root]=1<<col;
        add[root]=1<<col;
        return;
    }
    down(root);
    int mid=l+r>>1;
    if (beg<=mid) change(root*2,l,mid,beg,end,col);
    if (end>mid) change(root*2+1,mid+1,r,beg,end,col);
    up(root);
}
inline int query(int root,int l,int r,int beg,int end)
{
    if (l>=beg&&r<=end) return tree[root];
    down(root);
    int mid=l+r>>1,res=0;
    if (beg<=mid) res|=query(root*2,l,mid,beg,end);
    if (end>mid) res|=query(root*2+1,mid+1,r,beg,end);
    up(root);
    return res;
}
inline int calc(int x)
{
    int res=0;
    while (x) 
    {
        if (x%2==1) res++;
        x>>=1;
    }
    return res;
}
int main()
{
    read(l); read(t); read(o);
    build(1,1,l);
    while (o--)
    {
        cin>>ch;
        if (ch=='C') 
        {
            read(x); read(y); read(z);
            if (x>y) swap(x,y);
            change(1,1,l,x,y,z); 
        }else
        {
            read(x); read(y);
            if (x>y) swap(x,y);
            write(calc(query(1,1,l,x,y))); putchar('\n');
        }
    }
    return 0;
}

 

posted @ 2018-02-26 13:58  空気力学の詩  阅读(281)  评论(0编辑  收藏  举报