您的位置:首页 > 其它

【bzoj 4548】【JZOJ 5229】 小奇的糖果

2017-07-14 20:52 351 查看

Description

有 N 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果包含所有的颜色。

对于 30% 的数据,N ≤ 100;

对于 60% 的数据,N ≤ 5000;

对于 100% 的数据,N ≤ 100000,K ≤ 100000,T ≤ 3。

Preface

比赛的时候一直以为是分治+数据结构套路题,不敢打

正解却是乱搞,说明不可陷入惯性思维,看起来类似的题,解法也可能大相径庭

30%

枚举线段两个端点,再O(n)按从上到下或从下到上的顺序扫描每一个点判断

O(n^3)

60%

正解写炸的

不知道有什么O(n^2logn)的做法,也不知道能不能过这一档

100%

考虑一个合法且尽量优的矩阵满足什么条件

其左右边界肯定顶着一对相同的颜色(被该颜色卡住而不能继续扩展)

方便叙述,此处只讨论在选择线段上方的情况

假若维护一条水平线,表示线段高度

水平线从下往上扫,线段的两个端点显然会不断往两边扩展

如果扫的时候遇到一个点,其颜色为x,那么它的贡献是什么?

那么这个点被删除,之后该颜色的限制放宽

其它线段的端点原本被该点卡住,现在可以扩展了,需要更新,可以用双向链表维护

同时为了查询区域点数,使用树状数组维护

从上往下扫类似

O(nlogn)

Think Further

考虑类似问题:同样是线段上方或下方,求最少包含多少个点,使得包含所有颜色?

大致idea:维护水平线扫描,同时不断将线段两端收紧

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=1e5+5;
void read(int &t)
{
t=0;
int p=1;char ch;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
if(ch=='-') p=-1;
for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
t*=p;
}
int n,m,num,ans,x
,jx
,jy
,c
,tr
,last
,L
,R
;
struct node
{
int x,y,z,id;
}a
,b
;
bool cmpx(node a,node b){return a.x<b.x;}
bool cmpy(node a,node b){return a.y<b.y;}
int lowbit(int x){return x&-x;}
void add(int x,int z)
{
for(;x<=n;x+=lowbit(x)) tr[x]+=z;
}
int query(int x)
{
int t=0;
for(;x;x-=lowbit(x)) t+=tr[x];
return t;
}
int get(int l,int r)
{
return query(r)-query(l-1);
}
void solve()
{
memset(last,0,sizeof(last));
sort(a+1,a+n+1,cmpx);
fo(i,1,n) add(a[i].x,1);
fo(i,1,n)
{
int id=a[i].id,lst=last[a[i].z];
L[id]=lst,R[id]=n+1;
if(lst) R[lst]=id;
ans=max(ans,get(x[lst]+1,x[id]-1));
last[a[i].z]=id;
}
fo(i,1,m) ans=max(ans,get(x[last[i]]+1,n));
sort(a+1,a+n+1,cmpy);
int lst=1;
for(int i=1,j=1;i<=n;i++)
{
int id=a[i].id;
for(;j<=n && a[j].y==a[i].y;j++) add(a[j].x,-1);
L[R[id]]=L[id],R[L[id]]=R[id];
ans=max(ans,get(x[L[id]]+1,x[R[id]]-1));
}
}
int main()
{
int _;
for(read(_);_;_--)
{
memset(a,0,sizeof(a));
ans=0;
read(n);read(m);
fo(i,1,n) read(a[i].x),read(a[i].y),read(a[i].z),a[i].id=i,jx[i]=a[i].x;
sort(jx+1,jx+n+1);
fo(i,1,n) x[i]=a[i].x=lower_bound(jx+1,jx+n+1,a[i].x)-jx;
x[n+1]=n+1;
solve();
fo(i,1,n) a[i].y=-a[i].y;
solve();
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: