POJ2777解题报告【线段树,二进制存储状态】

题目地址:

  http://poj.org/problem?id=2777

题目概述:

  给一块长度为L的板子,有两种操作,第一种将A到B刷成颜色C,第二种询问A到B一共有多少种颜色。颜色数小于等于30。

大致思路:

  首先很容易发现线段树可以解决问题,不过怎么储存颜色呢?我们发现颜色总数很少,于是可以为2进制位来表示颜色,问题就可以很好地解决了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <ctime>
#include <map>
#include <stack>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

#define sacnf scanf
#define scnaf scanf
#define maxn  100010
#define maxm 26
#define inf 1061109567
#define Eps 0.00001
const double PI=acos(-1.0);
#define mod 7
#define MAXNUM 10000
void Swap(int &a,int &b) {int t=a;a=b;b=t;}
int Abs(int x) {return (x<0)?-x:x;}
typedef long long ll;
typedef unsigned int uint;

struct node
{
    int Set_flag,color;
} tree[maxn*3];

int t,p2[32];

void build_tree(int l,int r,int dir)
{
    tree[dir].color=(1<<1);tree[dir].Set_flag=0;
    if(l==r) return;
    int m=(l+r)>>1;
    build_tree(l,m,dir*2);
    build_tree(m+1,r,dir*2+1);
}

void pushdown(int l,int r,int dir)
{
    if(l!=r)
    {
        tree[dir*2].Set_flag=tree[dir].Set_flag;
        tree[dir*2+1].Set_flag=tree[dir].Set_flag;
        tree[dir*2].color=tree[dir*2+1].color=(1<<tree[dir].Set_flag);
    }
    tree[dir].color=(1<<tree[dir].Set_flag);
    tree[dir].Set_flag=0;
}

void Set(int l,int r,int dir,int sl,int sr,int c)
{
    if(sr<l||r<sl) return;
    if(sl<=l&&r<=sr)
    {
        tree[dir].Set_flag=c;
        tree[dir].color=(1<<c);
        return;
    }
    if(tree[dir].Set_flag!=0) pushdown(l,r,dir);
    int m=(l+r)>>1;
    Set(l,m,dir*2,sl,sr,c);
    Set(m+1,r,dir*2+1,sl,sr,c);
    tree[dir].color=(tree[dir*2].color|tree[dir*2+1].color);
}

int query(int l,int r,int dir,int ql,int qr)
{
    if(qr<l||r<ql) return 0;
    if(tree[dir].Set_flag!=0) pushdown(l,r,dir);
    if(ql<=l&&r<=qr) return tree[dir].color;
    int m=(l+r)>>1,t1,t2;
    t1=query(l,m,dir*2,ql,qr);
    t2=query(m+1,r,dir*2+1,ql,qr);
    return (t1|t2);
}

void debug(int n)
{
    for(int i=1;i<2*n;i++)
    {
        printf("%d ",tree[i].Set_flag);
        /*for(int j=1;j<=t;j++)
            if(tree[i].color[j]!=0) printf("%d,",j);
        printf("
");*/
    }
    printf("
");
}

int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    //clock_t st=clock();
    int l,o;p2[0]=1;
    for(int i=1;i<=30;i++) p2[i]=p2[i-1]*2;
    while(~scanf("%d%d%d",&l,&t,&o))
    {
        build_tree(1,l,1);
        while(o--)
        {
            getchar();char c;int a,b,p;
            scanf("%c%d%d",&c,&a,&b);
            if(a>b) Swap(a,b);
            if(c=='C')
            {
                scanf("%d",&p);
                Set(1,l,1,a,b,p);
            }
            else if(c=='P')
            {
                int ans=query(1,l,1,a,b);
                int cnt=0;
                for(int i=1;i<=t;i++)
                    if((ans&p2[i])==p2[i]) cnt++;
                printf("%d
",cnt);
            }
            //debug(l);
        }
    }
    //clock_t ed=clock();
    //printf("

Time Used : %.5lf Ms.
",(double)(ed-st)/CLOCKS_PER_SEC);
    return 0;
}
原文地址:https://www.cnblogs.com/CtrlKismet/p/6590598.html