HDU 6183 Color it cdq分治 + 线段树 + 状态压缩

Color it

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)

Problem Description

Do you like painting? Little D doesn‘t like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format of these operations is as follows.

0 : clear all the points.

1 x y c : add a point which color is c at point (x,y).

2 x y1 y2 : count how many different colors in the square (1,y1) and (x,y2). That is to say, if there is a point (a,b) colored c, that 1≤a≤x and y1≤b≤y2, then the color c should be counted.

3 : exit.

Input

The input contains many lines.

Each line contains a operation. It may be ‘0‘, ‘1 x y c‘ ( 1≤x,y≤106,0≤c≤50 ), ‘2 x y1 y2‘ (1≤x,y1,y2≤106 ) or ‘3‘.

x,y,c,y1,y2 are all integers.

Assume the last operation is 3 and it appears only once.

There are at most 150000 continuous operations of operation 1 and operation 2.

There are at most 10 operation 0.

Output

For each operation 2, output an integer means the answer .

Sample Input

0

1 1000000 1000000 50

1 1000000 999999 0

1 1000000 999999 0

1 1000000 1000000 49

2 1000000 1000000 1000000

2 1000000 1 1000000
0

1 1 1 1

2 1 1 2

1 1 2 2

2 1 1 2

1 2 2 2

2 1 1 2

1 2 1 3

2 2 1 2

2 10 1 2

2 10 2 2

0
1 1 1

1
2 1 1

1
1 1 2

1
2 1 1

2
1 2 2

1
2 1 1

2
1 2 1

1
2 2 1

2
2 10

1 2
2 10

2 2

3

Sample Output

2
3
1
2
2
3
3
1
1
1
1
1
1
1

题解:

  对于加入的点,我把第一维, x 进行排序, cdq分治优化时间这一维,其余部分用线段树

  因为只有50中颜色,我将每一位颜色进行二进制压缩,当作一个数存在线段树里

  利用线段树查询一个区间有多少不同的颜色(位运算)

  

#include <bits/stdc++.h>

inline int read(){int x=0,f=1;char ch=getchar();while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}return x*f;}
using namespace std;
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
const int N = 1e6 + 10;

namespace IO {
    const int MX = 4e7; //1e7占用内存11000kb
    char buf[MX]; int c, sz;
    void begin() {
        c = 0;
        sz = fread(buf, 1, MX, stdin);
    }
    inline bool read(int &t) {
        while(c < sz && buf[c] != ‘-‘ && (buf[c] < ‘0‘ || buf[c] > ‘9‘)) c++;
        if(c >= sz) return false;
        bool flag = 0; if(buf[c] == ‘-‘) flag = 1, c++;
        for(t = 0; c < sz && ‘0‘ <= buf[c] && buf[c] <= ‘9‘; c++) t = t * 10 + buf[c] - ‘0‘;
        if(flag) t = -t;
        return true;
    }
}

struct ss{
    int op,x,y,z,id;
    long long ans;
    ss(int op = 0,int x = 0,int y = 0,int z = 0,int id = 0,long long ans = 0) : op(op), x(x), y(y), z(z), id(id), ans(ans) {}
}Q[N],t[N];

bool cmp(ss s1,ss s2) { if(s1.x == s2.x) return s1.op < s2.op;else return s1.x < s2.x; }

int n,mx,san[N];
void init() {n = 0;}
long long v[N * 20];

void update(int i,int ll,int rr,int x,long long c,int ff) {
    if(ll == rr && x == ll) {if(!ff)v[i] |= 1LL<<c;else v[i] = c;return ;}
    if(x <= mid) update(ls,ll,mid,x,c,ff);
    else update(rs,mid+1,rr,x,c,ff);
    v[i] = v[ls] | v[rs];
}
long long ask(int i,int ll,int rr,int x,int y) {
    if(x > y) return 0;
    if(ll == x && rr == y) return v[i];
    if(y <= mid) return ask(ls,ll,mid,x,y);
    else if(x > mid) return ask(rs,mid+1,rr,x,y);
    else return (ask(ls,ll,mid,x,mid) | ask(rs,mid+1,rr,mid+1,y));
}
void cdq(int ll,int rr) {
    if(ll == rr) return ;
    for(int i = ll; i <= rr; ++i) {
        if(Q[i].id <= mid && Q[i].op == 1)
            update(1,1,mx,Q[i].y,Q[i].z,0);
        else if(Q[i].id > mid && Q[i].op == 2)
            Q[i].ans |= ask(1,1,mx,Q[i].y,Q[i].z);
    }
    for(int i = ll; i <= rr; ++i) {
        if(Q[i].id <= mid && Q[i].op == 1)
            update(1,1,mx,Q[i].y,0,1);
    }
    int L1 = ll, R1 = mid+1;
    for(int i = ll; i <= rr; ++i) {
        if(Q[i].id <= mid) t[L1++] = Q[i];
        else t[R1++] = Q[i];
    }
    for(int i = ll; i <= rr; ++i) Q[i] = t[i];
    cdq(ll,mid);cdq(mid+1,rr);
}
void solve() {
    if(n == 0) return ;
    int cny = 0;
    for(int i = 1; i <= n; ++i) {
        if(Q[i].op == 1) san[++cny] = Q[i].y;
        else {
            san[++cny] = Q[i].y;
            san[++cny] = Q[i].z;
        }
    }
    sort(san+1,san+cny+1);
    int SA = unique(san+1,san+cny+1) - san - 1;
    for(int i = 1; i <= n; ++i) {
        if(Q[i].op == 1) Q[i].y = lower_bound(san+1,san+SA+1,Q[i].y) - san;
        else {
            Q[i].y = lower_bound(san+1,san+SA+1,Q[i].y) - san;
            Q[i].z = lower_bound(san+1,san+SA+1,Q[i].z) - san;
        }
    }
    mx = SA;
    sort(Q+1,Q+n+1,cmp);
    cdq(1,n);
    for(int i = 1; i <= n; ++i) {
        if(Q[i].op == 2) {
            int sum = 0;
            for(int j = 0; j <= 50; ++j)
                if((Q[i].ans >> j) & 1) sum++;
            printf("%d\n",sum);
        }
    }
}
int op,x,z,y;
int main() {
    IO::begin();
    while(1) {
        IO::read(op);
        if(op == 3 || op == 0) {
            solve();
            init();
            if(op == 3) return 0;
            continue;
        }
        IO::read(x);
        IO::read(y);
        IO::read(z);
        Q[++n] = ss(op,x,y,z,n,0);
    }
    return 0;
}
时间: 2024-12-28 16:25:02

HDU 6183 Color it cdq分治 + 线段树 + 状态压缩的相关文章

hdu 1556:Color the ball(线段树,区间更新,经典题)

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7941    Accepted Submission(s): 4070 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电

hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the h

ACdream1157 Segments(CDQ分治 + 线段树)

题目这么说的: 进行如下3种类型操作:1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]2)C i (1-base) 删除第i条增加的线段,保证每条插入线段最多插入一次,且这次删除操作一定合法3) Q L R(1 <= L <= R <= 1000000000) 查询目前存在的线段中有多少条线段完全包含[L,R]这个线段,线段X被线段Y完全包含即LY <= LX <= RX <= RY) 初学CDQ分治是看了B

HDU 1556 Color the ball(线段树:区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1556 题意: N个气球,每次[a,b]之间的气球涂一次色,统计每个气球涂色的次数. 思路: 这道题目用树状数组和线段树都可以,拿这道题来入门一下线段树的区间更新. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 1000

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

Codechef SEP14 QRECT cdq分治+线段树

题意 支持删除矩阵.插入矩阵.查询当前矩阵与之前有多少个矩阵相交 算相交的时候容斥一下:相交矩形数 = 总矩形数-X轴投影不相交的矩形数-Y轴投影不相交的矩形数-XY轴投影下都不相交的矩形数 最后一项cdq分治解决 不是我的程序--->http://wyfcyx.is-programmer.com/posts/190325.html

HDU - 1556 Color the ball(线段树和树状数组)

题意:n个气球,n个操作(每次给区间[a,b]的气球涂颜色),求最后每个气球被涂颜色的次数. n可以取到100000,所以如果想for,for的话,就 爆!爆!爆! 1.线段树做法: 一道简单的线段树,做了好久都没做出来,果然自己还是太菜了... 创建一棵线段树,把里面的涂色次数对应的值都初始化为0. 更新的时候,找到那个要涂色的区间,涂色次数+1. 询问的时候从上往下找到那个区间,每次把值都递归出来. 1 #define LC(a) ((a<<1)+1) 2 #define RC(a) ((

POJ P2777 Count Color——线段树状态压缩

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 positive integer, so we can evenly d

POJ 2777 Count Color (线段树 + 状态压缩)

题目 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 positive integer, so we can evenly divide the