Hdu-6183 Color it(cdq分治)

185 篇文章 0 订阅
116 篇文章 0 订阅
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 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
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


分析:颜色只有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++;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值