• [BZOJ4548] 小奇的糖果


    问题描述

    平面上有n个点,每个点有一种颜色。对于某一条线段,选择所有其上方或下方的点。求:在不包含所有颜色的点的前提下,选择的点数最多是多少。(本题中如果存在某颜色没有相应的点,那么选择任何线段都不算做包含所有颜色)

    输入格式

    包含多组测试数据,第一行输入一个正整数 T 表示测试数据组数。

    接下来 T 组测试数据,对于每组测试数据,第一行输入两个正整数 N、K,分别表示点数和颜色数。

    接下来 N 行,每行描述一个点,前两个数 x, y (|x|, |y| ≤ 2^30 - 1) 描述点的位置,最后一个数 z (1 ≤ z ≤ k) 描述点的颜色。

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

    输出格式

    对于每组数据在一行内输出一个非负整数 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

    解析

    题目的意思就是求一个不包含某一种颜色的点的区域,也就是求不包含这种颜色的极大子矩形。

    不妨先考虑求线段下方的点。那么,对于一个点,它的极大子矩形就是如下图所示的这样一个区域:

    其中ABC三点颜色相同,且BC是x坐标最靠近A的点。这样就保证了子矩形中没有与A颜色相同的点。那么怎样求点的数量呢?可以先离散化x坐标,然后用树状数组维护每个x坐标上有几个点即可。另外,要按y坐标从小到大加入树状数组中,保证每次求区间和时都是在线段以下的点。至于求一个点在x轴上最近的两点可以用STL的set实现。

    求线段上方的只需要将y坐标取相反数然后进行同样的操作即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <set>
    #include <algorithm>
    #include <cstring>
    #define int long long
    #define N 100002
    using namespace std;
    struct node{
    	int x,y,col;
    }a[N];
    int t,n,m,i,tmp[N],c[N],ans;
    int read()
    {
    	char c=getchar();
    	int w=0,f=1;
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w*f;
    }
    int my_comp(const node &a,const node &b)
    {
    	return a.y<b.y;
    }
    int lowbit(int x)
    {
    	return x&(-x);
    }
    void add(int x,int y)
    {
    	for(int i=x;i<=n;i+=lowbit(i)) c[i]+=y;
    }
    int ask(int x)
    {
    	int ans=0;
    	for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i];
    	return ans;
    }
    void work()
    {
    	set<int> s[N];
    	int i=1,j=1;
    	memset(c,0,sizeof(c));
    	for(int i=1;i<=m;i++) s[i].insert(0),s[i].insert(n+1);
    	while(i<=n){
    		while(a[j].y==a[i].y) j++;
    		for(int k=i;k<j;k++){
    			int l=*(--s[a[k].col].upper_bound(a[k].x));
    			int r=*(s[a[k].col].lower_bound(a[k].x))-1;
    			ans=max(ans,ask(r)-ask(l));
    		}
    		for(int k=i;k<j;k++){
    			add(a[k].x,1);
    			s[a[k].col].insert(a[k].x);
    		}
    		i=j;
    	}
    	for(i=1;i<=m;i++){
    		set<int>::iterator it1=s[i].begin(),it2;
    		while(1){
    			it2=it1;it2++;
    			if(it2==s[i].end()) break;
    			ans=max(ans,ask((*it2)-1)-ask(*it1));
    			it1++;
    		}
    	}
    }
    signed main()
    {
    	t=read();
    	while(t--){
    		ans=0;
    		n=read();m=read();
    		for(i=1;i<=n;i++){
    			a[i].x=read(),a[i].y=read(),a[i].col=read();
    			tmp[i]=a[i].x;
    		}
    		sort(tmp+1,tmp+n+1);
    		int n1=unique(tmp+1,tmp+n+1)-tmp-1;
    		for(i=1;i<=n;i++) a[i].x=lower_bound(tmp+1,tmp+n1+1,a[i].x)-tmp;
    		sort(a+1,a+n+1,my_comp);
    		work();
    		for(i=1;i<=n;i++) a[i].y=-a[i].y;
    		sort(a+1,a+n+1,my_comp);
    		work();
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    LeetCode——打家劫舍问题
    LeetCode——无重叠区间
    LeetCode——岛屿数量
    LeetCode——石子游戏
    LeetCode——最长回文子序列
    LeetCode——高层扔鸡蛋*
    LeetCode——零钱兑换
    LeetCode刷题之BFS和DFS
    没有学历,四步加入谷歌
    坚持编程
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11691366.html
Copyright © 2020-2023  润新知