Hdu-6183 Color it(cdq分治)

来源:互联网 发布:三维接线软件 编辑:程序博客网 时间:2024/06/10 17:24
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.

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

2xy1y2 : 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 1ax and y1by2, 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' ( 1x,y106,0c50 ), '2 x y1 y2' (1x,y1,y2106 ) 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
01 1000000 1000000 501 1000000 999999 01 1000000 999999 01 1000000 1000000 492 1000000 1000000 10000002 1000000 1 100000001 1 1 12 1 1 21 1 2 22 1 1 21 2 2 22 1 1 21 2 1 32 2 1 22 10 1 22 10 2 201 1 1 12 1 1 11 1 2 12 1 1 21 2 2 12 1 1 21 2 1 12 2 1 22 10 1 22 10 2 23
Sample Output
23122331111111


分析:颜色只有50个,可以考虑用一个long long来表示,:这题的查询操作很特殊,每次查询的是一个紧贴着y轴的矩阵中的颜色数,所以我们只需要用线段树维护纵轴方向的颜色集合,那么每次查询就是横轴上的一个前缀和,修改操作只要用cdq分治对时间进行分治就把修改时间这一维忽略了,剩下的就是按横标从左到右动态插入和查询答案,直接用动态开点线段树解决,总复杂度n*logn(线段树)*logn(cdq对时间的分治)。


#include <bits/stdc++.h>using namespace std;const int N = 2e6;typedef long long ll;inline int read(){    char c=getchar();int x=0,f=1;    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}    return x*f;}   class thing{public:int op,x,y,z,t,lab;friend bool operator < (const thing &a,const thing &b){if(a.x != b.x) return a.x < b.x;return a.t < b.t;}}job[N],work[N],tmp[N];int n,num,cnt,root,tot,ch[N*2][2];ll ans[N],mask[N*2];int Count(ll x){int cnt = 0;while(x){cnt++;x -= x & (-x);}return cnt;}void Insert(int &u,int l,int r,int x,int val){if(!u) u = ++cnt;mask[u] |= 1ll<<val;if(l == r) return;int mid = (l+r)>>1;if(x <= mid) Insert(ch[u][0],l,mid,x,val);else Insert(ch[u][1],mid+1,r,x,val);}ll Query(int u,int l,int r,int x,int y){if(!u) return 0;if(l == x && r == y) return mask[u];int mid = (l+r)>>1;if(y <= mid) return Query(ch[u][0],l,mid,x,y);else  if(x <= mid) return Query(ch[u][0],l,mid,x,mid) | Query(ch[u][1],mid+1,r,mid+1,y); else return Query(ch[u][1],mid+1,r,x,y);}void Del(int &u){if(!u) return;Del(ch[u][0]);Del(ch[u][1]);mask[u] = 0;u = 0;}void cdq(int l,int r){if(l >= r) return;int mid = (l+r)>>1;for(int i = l;i <= r;i++) if(work[i].op == 1 && work[i].t <= mid) Insert(root,1,1e6,work[i].y,work[i].z); else   if(work[i].op == 2 && work[i].t > mid) ans[work[i].lab] |= Query(root,1,1e6,work[i].y,work[i].z);Del(root);cnt = 0;int l1 = l-1,r1 = mid;for(int i = l;i <= r;i++) if(work[i].t <= mid) tmp[++l1] = work[i]; else tmp[++r1] = work[i];for(int i = l;i <= r;i++) work[i] = tmp[i]; cdq(l,mid);cdq(mid+1,r);}void deal(int l,int r){if(l > r) return;n = r - l + 1;num = 0;for(int i = l;i <= r;i++)  if(job[i].op == 2) job[i].lab = ++num;for(int i = l;i <= r;i++) {work[i-l+1] = job[i];work[i-l+1].t = i-l+1;}sort(work+1,work+1+n);cdq(1,n);for(int i = 1;i <= num;i++) {cout<<Count(ans[i])<<endl;ans[i] = 0;}}int main(){int l = 1,r = 0,op;while((op = read()) != 3){job[++tot].op = op;if(op == 1 || op == 2) job[tot].x = read(),job[tot].y = read(),job[tot].z = read();}job[++tot].op = 0;for(int T = 1;T <= tot;T++){if(job[T].op == 0) {deal(l,r);l = T+1;r = T;} else r++;}}