「省选模拟赛」小奇的糖果
原题:EAST! 模拟赛 Round XV 呓语
「题目背景」
小奇不小心让糖果散落到了地上,它对着满地的彩色糖果胡思乱想。
「问题描述」
有 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。
题解
维护树状数组实现查询横坐标在一段区间内的点的个数。
维护双向链表实现查询一个点左(右)边横坐标最大(小)的与它颜色相同
的点。
下面只考虑取线段下方的点的情况:
1.枚举没有取到的颜色,找出所有不包含这种颜色的区间,更新答案。
2.按照纵坐标从大到小枚举所有的点,分别在树状数组和双向链表中删除当前点,并利用这个点左右两边和它颜色相同的点之间的区间内点的个数更新答案。
将所有点的纵坐标取相反数,按照上述方式即可求出只取线段上方的点时的答案。
时间复杂度 O(n*log n)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long #define mod 10000007 using namespace std; ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int ans; int T,n,K; struct data{ int x,y,z; int id; }p[100005]; int x[100005]; int disc[100005],t[100005]; int last[100005],l[100005],r[100005]; void add(int x,int val) { for(;x<=n+1;x+=x&-x) t[x]+=val; } int query(int x) { int ans=0; for(;x>0;x-=x&-x) ans+=t[x]; return ans; } bool cmpx(data a,data b) { return a.x<b.x; } bool cmpy(data a,data b) { return a.y<b.y; } void update(int l,int r) { if(l>r)return; int tmp=query(r)-query(l-1); ans=max(tmp,ans); } void solve() { x[0]=0;x[n+1]=n+1; memset(last,0,sizeof(last)); memset(t,0,sizeof(t)); sort(p+1,p+n+1,cmpx); for(int i=1;i<=n;i++) add(p[i].x,1); for(int i=1;i<=n;i++) { int t=p[i].id,L=last[p[i].z]; l[t]=L;r[t]=n+1; if(L)r[L]=t; update(x[L]+1,x[t]-1); last[p[i].z]=t; } for(int i=1;i<=K;i++) update(x[last[i]]+1,n+1); sort(p+1,p+n+1,cmpy); for(int i=1,j=1;i<=n;i++) { int t=p[i].id; while(j<=n&&p[j].y==p[i].y) { add(p[j].x,-1); j++; } l[r[t]]=l[t];r[l[t]]=r[t]; update(x[l[t]]+1,x[r[t]]-1); } } int main() { freopen("candy.in","r",stdin); freopen("candy.out","w",stdout); T=read(); while(T--) { ans=0; n=read();K=read(); for(int i=1;i<=n;i++) { p[i].x=read(),p[i].y=read(),p[i].z=read(); p[i].id=i; } for(int i=1;i<=n;i++) disc[i]=p[i].x; sort(disc+1,disc+n+1); for(int i=1;i<=n;i++) { p[i].x=lower_bound(disc+1,disc+n+1,p[i].x)-disc; x[i]=p[i].x; } solve(); for(int i=1;i<=n;i++) p[i].y=-p[i].y; solve(); printf("%d\n",ans); } return 0; } |