【BZOJ4548】小奇的糖果
「题目背景」
小奇不小心让糖果散落到了地上,它对着满地的彩色糖果胡思乱想。
「问题描述」
有 N 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色。
「输入格式」
包含多组测试数据,第一行输入一个正整数 T 表示测试数据组数。
接下来 T 组测试数据,对于每组测试数据,第一行输入两个正整数 N、K,分别表示点数和颜色数。
接下来 N 行,每行描述一个点,前两个数 x, y (|x|, |y| ≤ 2^30 – 1) 描述点的位置,最后一个数 z (1 ≤ z ≤ k) 描述点的颜色。
「输出格式」
对于每组数据在一行内输出一个非负整数 ans,表示答案。
「样例输入」
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
「样例输出」
5
「数据范围」
对于 30% 的数据,N ≤ 100;
对于 60% 的数据,N ≤ 5000;
对于 100% 的数据,N ≤ 100000,K ≤ 100000,T ≤ 3。
第N道小奇系列的题目了(之前好像也做过一道小奇的糖果来着,不过那是IOI改编,有点难)
模拟考的时候写了暴力居然没有分(!)
下面是自己写的题解:
- 这是在糖果是撒在二维平面里的,所以我们可以通过其中一维的坐标离散化,然后通过枚举,转成单一一维里的问题。
- 把横坐标离散化掉,按横坐标从左到右,把横坐标相邻的糖果用双向的链表串在一起(对于有不同颜色的序列,这样的操作很常见哦,记下来记下来)。
- 所以每一次在两个相同颜色的糖果之间数一下其它糖果的数量,就可以来更新ans了,可以用树状数组来维护区间里的糖果数量。
- 然后想象一条扫描线,从下到上扫一遍,每一次把扫描线上的点屏蔽掉,再更新一次答案,这样就可以完成对于水平线上糖果的更新了。
- 那水平线下的怎么更新呢?一样的嘛,为了减少编程复杂度,我们把纵坐标取相反数,用一样的办法再做一次就可以了。
代码~
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<algorithm>
6
7 #define For(i,a,b) for(register int i=a;i<=b;++i)
8 #define Re register
9 #define Pn putchar('\n')
10 using namespace std;
11 const int N=1e5+10;
12 int Lc[N],Rc[N],lst[N];
13 int X[N],sX[N];
14 struct Point{
15 int x,y,cl,id;
16 }pt[N];
17 int c[N],n,m,x,y,Kx,ans=0;
18
19 inline void read(int &v){
20 v=0; bool fg=0;
21 char c=getchar(); if(c=='-')fg=1;
22 while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;}
23 while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar(); if(c=='-')fg=1;}
24 if(fg)v=-v;
25 }
26 void write(int x){
27 if(x>9)write(x/10);
28 int xx=x%10;
29 putchar(xx+'0');
30 }
31 bool cmpX(const Point &a,const Point &b){
32 return a.x<b.x;
33 }
34 bool cmpY(const Point &a,const Point &b){
35 return a.y<b.y;
36 }
37
38
39 int LB(int x){
40 return x&(-x);
41 }
42 void upD(int k,int dt){
43 for(Re int i=k;i<=n;i+=LB(i)){
44 c[i]+=dt;
45 }
46 }
47 int Qry(int k){
48 int ans=0;
49 for(Re int i=k;i>=1;i-=LB(i)){
50 ans+=c[i];
51 }
52 return ans;
53 }
54
55 void makeA(int lx,int rx){
56 if(lx>rx)return;
57 int tp=Qry(rx)-Qry(lx-1);
58 ans=max(tp,ans);
59 }
60 void PickupCandy(){
61
62 X[0]=0; X[n+1]=n+1;
63 memset(lst,0,sizeof(lst));
64 memset(c,0,sizeof(c));
65
66 sort(pt+1,pt+n+1,cmpX);
67
68 For(i,1,n){
69 upD(pt[i].x,1);
70 }
71
72 For(i,1,n){
73 int ID=pt[i].id;
74 int prC=lst[pt[i].cl];
75 Lc[ID]=prC; Rc[ID]=n+1;
76 if(prC) Rc[prC]=ID;
77 makeA(X[prC]+1,X[ID]-1);
78 lst[pt[i].cl]=ID;
79 }
80 For(i,1,Kx){
81 makeA(X[lst[i]]+1,X[n+1]);
82 }
83
84 sort(pt+1,pt+n+1,cmpY);
85
86 int Px=1;
87 For(i,1,n){
88 while(Px<=n&&pt[i].y==pt[Px].y){
89 upD(X[pt[Px].id],-1);
90 Px++;
91 }
92 int ID=pt[i].id;
93 Lc[Rc[ID]]=Lc[ID]; Rc[Lc[ID]]=Rc[ID];
94 makeA(X[Lc[ID]]+1,X[Rc[ID]]-1);
95 }
96 return;
97 }
98
99 int main(){
100 //freopen("candy.in","r",stdin);
101 //freopen("candy.out","w",stdout);
102 int T; read(T);
103 while(T--){
104 read(n); read(Kx);
105 ans=0;
106 For(i,1,n){
107 read(pt[i].x); read(pt[i].y); read(pt[i].cl);
108 pt[i].id=i;
109 sX[i]=pt[i].x;
110 }
111 sort(sX+1,sX+n+1);
112 For(i,1,n){
113 X[i]=lower_bound(sX+1,sX+n+1,pt[i].x)-sX;
114 pt[i].x=X[i];
115 }
116 PickupCandy();
117 For(i,1,n)pt[i].y*=-1;
118 PickupCandy();
119 write(ans); Pn;
120 }
121 // fclose(stdin); fclose(stdout);
122 return 0;
123 }