bzoj 4548: 小奇的糖果 && bzoj 3658: Jabberwocky(雙向連結串列+樹狀陣列)
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 2Sample 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;
}