1. 程式人生 > >bzoj 4548: 小奇的糖果 && bzoj 3658: Jabberwocky(雙向連結串列+樹狀陣列)

bzoj 4548: 小奇的糖果 && bzoj 3658: Jabberwocky(雙向連結串列+樹狀陣列)

Time Limit: 20 Sec  Memory Limit: 1024 MB
Submit: 263  Solved: 107
[Submit][Status][Discuss]

Description

平面上有n個點,每個點有k種顏色中的一個。
你可以選擇一條水平的線段獲得在其上方或其下方的所有點,如圖所示:

請求出你最多能夠得到多少點,使得獲得的點並不包含所有的顏色。
   

Input

包含多組測試資料,第一行輸入一個數T表示測試資料組數。
接下來T組測試資料,對於每組測試資料,第一行輸入兩個數n,k,分別表示點的個數和顏色數。
接下來n行每行描述一個點,前兩個數z,y(lxl,lyl≤2^32-1)描述點的位置,最後一個數z(1≤z≤K)描述點的顏色。

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

將問題簡化:

假設線段只有可能在在座標系的最下面or最上面,並且每個x座標都不同

那麼只要用雙向連結串列O(n)模擬一下就好了,所有座標點按x大小排序,第p個節點就是從小到大第p個座標

每個節點p記錄一個p.pre和p.next,分別表示在左邊or右邊顏色相同且離得最近的節點id,

答案就是max(max(p.next-1-p, p-1-p.pre))  (1<=p<=n),也就是兩個相鄰的相同顏色節點之間距離的最大值

如果存在x座標相同的點

要先將x座標離散化,並且上面的那個式子就會有問題,因為x座標相同的點只有可能同時取或同時不取

這樣就不能直接求p.next和p的間隔了,而是找到x座標剛好小於p.next點以及x座標剛好大於p點的兩點之間有多少個點,求這個的最大值,因為離散化過了,這個很好處理

p和p.pre之間同理

顯然這題線段沒有限制,不一定在最下面or最上面

那樣的話我們需要按y座標從小到大排序(如果相同再按x排序)

求出來上面的東西之後再從下到上掃描,逐個刪點,每刪一個點求一次最大值

因為是雙向連結串列,所以刪點是O(1)的,並且只有這段變大的區間會影響答案

不過因為中間有些點已經消失了,所以不能直接通過相減求間隔,要用樹狀陣列儲存哪些還沒有被刪

別忘了還要從上往下再來一次

總複雜度O(n)+O(2nlogn)=O(nlogn)

注意這題有個坑,假設有k種顏色但是下面出現的不同顏色數量都不到k個,那麼答案就是n(也就是所有點全部選中)還有bzoj3658這題的資料比較強,雖然是一模一樣的題,但一開始我4548AC了,3658WA,不是long long的問題

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct
{
	LL pre;
	LL nxt;
}Line;
Line h[100005];
typedef struct Res
{
	LL x, y;
	LL id;
	LL col;
	bool operator < (const Res &b) const
	{
		if(id<b.id)
			return 1;
		return 0;
	}
}Res;
Res s[100005];
LL cnt, Hash[100005], tre[100005], temp[100005], y[100005], col[100005];
bool compx(Res a, Res b)
{
	if(a.x<b.x)
		return 1;
	return 0;
}
bool compy(Res a, Res b)
{
	if(a.y<b.y || a.y==b.y && a.x<b.x)
		return 1;
	return 0;
}
void Update(LL x, LL val)
{
	while(x<=cnt)
	{
		tre[x] += val;
		x += x&-x;
	}
}
LL Query(LL x)
{
	LL sum = 0;
	while(x)
	{
		sum += tre[x];
		x -= x&-x;
	}
	return sum;
}
int main(void)
{
	LL T, i, n, m, ans;
	scanf("%lld", &T);
	while(T--)
	{
		cnt = 0;
		scanf("%lld%lld", &n, &m);
		memset(col, 0, sizeof(col));
		for(i=1;i<=n;i++)
		{
			scanf("%lld%lld%lld", &s[i].x, &s[i].y, &s[i].col);
			s[i].id = i;
			Hash[++cnt] = s[i].x;
			col[s[i].col] = 1;
		}
		for(i=1;i<=m;i++)
		{
			if(col[i]==0)
				break;
		}
		if(i<=m)
		{
			printf("%lld\n", n);
			continue;
		}
		sort(Hash+1, Hash+cnt+1);
		cnt = unique(Hash+1, Hash+cnt+1)-(Hash+1);
		s[n+1].x = cnt+1;
		for(i=1;i<=n;i++)
			s[i].x = lower_bound(Hash+1, Hash+cnt+1, s[i].x)-Hash;

		ans = 0;
		sort(s+1, s+n+1, compx);
		memset(temp, 0, sizeof(temp));
		for(i=1;i<=n;i++)
		{
			Update(s[i].x, 1);
			h[i].pre = temp[s[i].col];
			s[i].id = i;
			temp[s[i].col] = i;
			ans = max(ans, Query(s[i].x-1)-Query(s[h[i].pre].x));
		}
		for(i=1;i<=n;i++)
			temp[i] = n+1;
		for(i=n;i>=1;i--)
		{
			h[i].nxt = temp[s[i].col];
			temp[s[i].col] = i;
			ans = max(ans, Query(s[h[i].nxt].x-1)-Query(s[i].x));
		}
		sort(s+1, s+n+1, compy);
		for(i=1;i<=n;i++)
			y[i] = s[i].id;
		sort(s+1, s+n+1);
		for(i=1;i<=n;i++)
		{
			Update(s[y[i]].x, -1);
			ans = max(ans, Query(s[h[y[i]].nxt].x-1)-Query(s[h[y[i]].pre].x));
			h[h[y[i]].nxt].pre = h[y[i]].pre;
			h[h[y[i]].pre].nxt = h[y[i]].nxt;
		}

		sort(s+1, s+n+1, compx);
		memset(temp, 0, sizeof(temp));
		for(i=1;i<=n;i++)
		{
			Update(s[i].x, 1);
			h[i].pre = temp[s[i].col];
			s[i].id = i;
			temp[s[i].col] = i;
			ans = max(ans, Query(s[i].x-1)-Query(s[h[i].pre].x));
		}
		for(i=1;i<=n;i++)
			temp[i] = n+1;
		for(i=n;i>=1;i--)
		{
			h[i].nxt = temp[s[i].col];
			temp[s[i].col] = i;
			ans = max(ans, Query(s[h[i].nxt].x-1)-Query(s[i].x));
		}
		sort(s+1, s+n+1, compy);
		for(i=1;i<=n;i++)
			y[i] = s[i].id;
		sort(s+1, s+n+1);
		for(i=n;i>=1;i--)
		{
			Update(s[y[i]].x, -1);
			ans = max(ans, Query(s[h[y[i]].nxt].x-1)-Query(s[h[y[i]].pre].x));
			h[h[y[i]].nxt].pre = h[y[i]].pre;
			h[h[y[i]].pre].nxt = h[y[i]].nxt;
		}
		printf("%lld\n", ans);
	}
	return 0;
}