1. 程式人生 > >【BZOJ4548】小奇的糖果 set(鏈表)+樹狀數組

【BZOJ4548】小奇的糖果 set(鏈表)+樹狀數組

style string output num true 感覺 100% 接下來 bzoj

【BZOJ4548】小奇的糖果

Description

有 N 個彩色糖果在平面上。小奇想在平面上取一條水平的線段,並拾起它上方或下方的所有糖果。求出最多能夠拾起多少糖果,使得獲得的糖果並不包含所有的顏色。

Input

包含多組測試數據,第一行輸入一個正整數 T 表示測試數據組數。

接下來 T 組測試數據,對於每組測試數據,第一行輸入兩個正整數 N、K,分別表示點數和顏色數。 接下來 N 行,每行描述一個點,前兩個數 x, y (|x|, |y| ≤ 2^30 - 1) 描述點的位置,最後一個數 z (1 ≤ z ≤ k) 描述點的顏色。 對於 100% 的數據,N ≤ 100000,K ≤ 100000,T ≤ 3

Output

對於每組數據在一行內輸出一個非負整數 ans,表示答案

Sample Input

1
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2

Sample Output

5

題解:一開始想的是:不包含所有顏色=有一種顏色不出現,所以我們枚舉不出現哪個顏色即可。而一個顏色出現的位置有很多,我們相當於用這些點將平面分成若幹個部分,然後在每個部分裏都統計一下點的個數即可。不過該怎麽分呢?蒟蒻就卡到這了,然而看大爺的博客發現可以分治。。。感覺神的不行。

所以還是來看一種簡單的方法吧!我們先只考慮向下的情況。我們將所有點按y值從小到大排序,然後從下往上一層一層的加入到平面中(一層一層指的是y值相同的點要同時加入)。在加入一個點之前,我們先用set找到與它顏色相同的,已經加入到平面中的點的,x值的前驅和後繼,然後用樹狀數組統計一下前驅到後繼之間這部分的點數,然後再將這個點加進去。最後可能有沒被統計過得部分,再查詢一遍所有點即可。

向上的情況呢?反過來做一遍即可。

PS:如果你將一個一個加點改成一個一個刪點,那就可以用鏈表來維護前驅後繼了~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#include <utility>
#define mp(A,B) make_pair(A,B)
using namespace std;
const int maxn=100010;
typedef pair<int,int> pii;
int n,m,nm,cnt,ans;
struct point
{
	int x,y,col;
}p[maxn];
struct node
{
	int val,org;
}num[maxn];
int v[maxn],vis[maxn],s[maxn],st[maxn];
set<int> S[maxn];
set<int>::iterator it;
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
bool cmpv(const node &a,const node &b)
{
	return a.val<b.val;
}
bool cmpy(const point &a,const point &b)
{
	return a.y<b.y;
}
inline void updata(int x)
{
	for(int i=x;i<=nm;i+=i&-i)	s[i]++;
}
inline int query(int x)
{
	int i,ret=0;
	for(i=x;i;i-=i&-i)	ret+=s[i];
	return ret;
}
inline void insert(int x)
{
	S[p[x].col].insert(p[x].x),updata(p[x].x),cnt+=(!vis[p[x].col]),vis[p[x].col]=1;
}
inline void calc(int x)
{
	int a,b;
	it=S[p[x].col].lower_bound(p[x].x),b=(it==S[p[x].col].end()?nm+1:(*it));
	it=S[p[x].col].upper_bound(p[x].x),a=(it==S[p[x].col].begin()?0:(*(--it)));
	ans=max(ans,query(b-1)-query(a));
}
inline void init()
{
	memset(vis,0,sizeof(vis)),memset(s,0,sizeof(s)),cnt=0;
	for(int i=1;i<=m;i++)	S[i].clear();
}
void work()
{
	n=rd(),m=rd(),nm=ans=0;
	int i,j,a,b;
	for(i=1;i<=n;i++)	num[i].val=rd(),num[i].org=i,p[i].y=rd(),p[i].col=rd();
	sort(num+1,num+n+1,cmpv);
	for(i=1;i<=n;i++)
	{
		if(i==1||num[i].val>num[i-1].val)	nm++;
		p[num[i].org].x=nm;
	}
	p[0].x=1,p[n+1].x=n;
	sort(p+1,p+n+1,cmpy);
	init();
	for(i=1;i<=n;i++)
	{
		st[st[0]=1]=i;
		while(i<n&&p[i+1].y==p[i].y)	st[++st[0]]=++i;
		for(j=1;j<=st[0];j++)	calc(st[j]);
		for(j=1;j<=st[0];j++)	insert(st[j]);
		if(cnt<m)	ans=max(ans,i);
	}
	for(i=1;i<=n;i++)
	{
		it=S[p[i].col].upper_bound(p[i].x),b=(it==S[p[i].col].end()?nm+1:(*it));
		it=S[p[i].col].lower_bound(p[i].x),a=(it==S[p[i].col].begin()?0:(*(--it)));
		ans=max(ans,query(b-1)-query(p[i].x)),ans=max(ans,query(p[i].x-1)-query(a));
	}
	init();
	for(i=n;i;i--)
	{
		st[st[0]=1]=i;
		while(i>1&&p[i-1].y==p[i].y)	st[++st[0]]=--i;
		for(j=1;j<=st[0];j++)	calc(st[j]);
		for(j=1;j<=st[0];j++)	insert(st[j]);
		if(cnt<m)	ans=max(ans,n-i+1);
	}
	for(i=1;i<=n;i++)
	{
		it=S[p[i].col].upper_bound(p[i].x),b=(it==S[p[i].col].end()?nm+1:(*it));
		it=S[p[i].col].lower_bound(p[i].x),a=(it==S[p[i].col].begin()?0:(*(--it)));
		ans=max(ans,query(b-1)-query(p[i].x)),ans=max(ans,query(p[i].x-1)-query(a));
	}
	printf("%d\n",ans);
}
int main()
{
	int T=rd();
	while(T--)	work();
	return 0;
}

【BZOJ4548】小奇的糖果 set(鏈表)+樹狀數組