[GYM102979C]Colorful Squares
壹、题目描述 ¶
贰、题解 ¶
先二分答案 转判定性问题。考虑扫描线,对于大小为 的正方形,先把 的所有点加入集合,再在 的时候把 加入的点从集合中删除。那么现在就是判断集合中是否存在一个 ,使得 里面有所有的 种颜色。
设有一个数据结构,其每个点 维护 的颜色种数,假设我们加入点为 ,那么它会增加该数据结构中的 中所有点维护区间的颜色种数,该操作即区间 ,过,可能这其中已经有些点包含了该点的颜色 ,故而,我们还需要对于每个颜色开一个 维护该颜色所有 的位置,插入 时,找到前驱和后继 ,那么我们最终修改的区间就是
最后统计时,只需查看是否存在某个位置维护的值为 即可,这和区间最大值差不过。撤销操作,其实就是区间减 .
关于数据结构的选择,显然我们可以使用线段树做到。时间复杂度 .
叁、参考代码 ¶
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <vector>
# include <set>
using namespace std;
// # define NDEBUG
# include <cassert>
namespace Elaina {
# define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
# define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
# define fi first
# define se second
# define mp(a, b) make_pair(a, b)
# define Endl putchar('\n')
# define mmset(a, b) memset(a, b, sizeof (a))
# define mmcpy(a, b) memcpy(a, b, sizeof (a))
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
template <class T> inline T fab(T x) { return x<0? -x: x; }
template <class T> inline void getmin(T& x, const T rhs) { x=min(x, rhs); }
template <class T> inline void getmax(T& x, const T rhs) { x=max(x, rhs); }
template <class T> inline T readin(T x) {
x=0; int f=0; char c;
while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
return f? -x: x;
}
template <class T> inline void writc(T x, char s='\n') {
static int fwri_sta[1005], fwri_ed=0;
if(x<0) putchar('-'), x=-x;
do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
putchar(s);
}
} using namespace Elaina;
const int maxn=2e5;
const int maxx=2.5e5;
const int inf=0x3f3f3f3f;
int n, k;
vector<pii>v[maxx+5];
inline void input() {
n=readin(1), k=readin(1);
int x, y, c;
rep(i, 1, n) {
x=readin(1), y=readin(1), c=readin(1);
v[x].push_back({y, c});
}
}
namespace saya {
int mx[maxx<<2|2];
int tag[maxx<<2|2]; // modify tag
bool cls[maxx<<2|2]; // clear tag
# define ls (i<<1)
# define rs (i<<1|1)
# define mid ((l+r)>>1)
# define _lhs ls, l, mid
# define _rhs rs, mid+1, r
inline void clear(int i) {
mx[i]=tag[i]=0, cls[i]=1;
}
inline void add(int i, int val) {
mx[i]+=val, tag[i]+=val;
}
inline void pushdown(int i) {
if(!cls[i] && !tag[i]) return;
if(cls[i]) clear(ls), clear(rs), cls[i]=0;
if(tag[i]) add(ls, tag[i]), add(rs, tag[i]), tag[i]=0;
}
inline void pushup(int i) {
mx[i]=max(mx[ls], mx[rs]);
}
void modify(int L, int R, int val, int i=1, int l=1, int r=maxx) {
// if(i==1) printf("modify :> L == %d, R == %d, val == %d\n", L, R, val);
if(L>R || r<L || l>R) return;
if(L<=l && r<=R) return add(i, val);
pushdown(i);
if(L<=mid) modify(L, R, val, _lhs);
if(mid<R) modify(L, R, val, _rhs);
pushup(i);
}
# undef ls
# undef rs
# undef mid
# undef _lhs
# undef _rhs
}
multiset<int>c[maxn+5];
inline bool check(int s) {
/** initialization */
saya::clear(1);
rep(i, 1, k) {
c[i].clear();
c[i].insert(-inf), c[i].insert(inf);
}
rep(x, 1, maxx) {
/** add part */
for(auto [y, col]: v[x]) {
c[col].insert(y);
auto it=c[col].find(y);
auto pre=it, suf=it; --pre, ++suf;
saya::modify(max(*pre+s+1, y), min(*suf-1, y+s), 1);
}
/** remove part */
if(x-s-1>=1) {
for(auto [y, col]: v[x-s-1]) {
auto it=c[col].find(y);
assert(it!=c[col].end()); // it should have found
auto pre=it, suf=it; --pre, ++suf;
saya::modify(max(*pre+s+1, y), min(*suf-1, y+s), -1);
c[col].erase(it); // should erase the iterator
}
}
// printf("When x == %d, mx == %d\n", x, saya::mx[1]);
if(saya::mx[1]==k) return true;
}
return false;
}
signed main() {
input();
int l=0, r=maxx, mid, ans=-1;
while(l<=r) {
mid=(l+r)>>1;
// printf("Now l == %d, r == %d, mid == %d\n", l, r, mid);
if(check(mid)) ans=mid, r=mid-1;
else l=mid+1;
} writc(ans);
return 0;
}
肆、关键之处 ¶
好像之前做机器人那道傻逼树套树也用过这种思路,但是当时没调出来就忽略了这种思路,现在想想居然还挺巧妙,与其说是扫描线,我倒觉得更像是动态地维护一个队列以及其中的点的信息吧?不过说成是两根扫描线也挺形象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现