给你一个 L*L 的矩形,里面有 n 个点,有各自的颜色。
然后问你有多少个端点是整点的矩形可以圈出所有颜色至少有一个点。
Rainbow Rectangles
题目大意
给你一个 L*L 的矩形,里面有 n 个点,有各自的颜色。
然后问你有多少个端点是整点的矩形可以圈出所有颜色至少有一个点。
思路
考虑枚举区间的边界,枚举上边界。
然后再枚举下边界,然后考虑有多少答案。
(因为这个时候已近 n2 了)
然后你发现不能 O(1),看看 O(n) 行不行。
首先发现如果 [l,r] 可以,那对于 x>r,[l,x] 都可以。
所以我们对于每个左边界,我们只要能求出最左的满足条件的右边界即可。
然后发现值域很大,所以要离散化,如果 xi,yi 代表离散化之后的位置值,设为 fi。
那贡献就是 (yi−yi−1)(L−fi+1),然后上下端点也可以滑动,所以还有 (xr+1−xr)(xl−xl−1)。
不过上面那个我们可以拆一下:
m∑i=1(yi−yi−1)(L−fi+1)
m∑i=1(yi−yi−1)(L+1)−m∑i=1(yi−yi−1)fi
ym(L+1)−m∑i=1(yi−yi−1)fi
那问题就是怎么求后面这个,也就是如何求 fi。
考虑考虑左边界右移。
那有的颜色会消失,你要找到右边第一个能出现的。
那我们可以设 nxti 为 i 这一列的所有颜色下一次出现的列的最大值。
然后转移就是 fi+1=max(fi,nxti),那其实就是 nxti 的前缀最大值。
那我们 O(n) 转移了,也就到了 n3。
考虑用下端点下手,能不能比如下端点往下,维护答案之类的。
那往下就是要加点,其实不好搞,我们考虑从下往上枚举下断点,那每次就是删点。
那我们可以用 set 记录每个颜色出现的列的坐标,那删除我们就找到上一个颜色是这一个的列,以及下一个。
如果上一个是 bef,下一个是 nxt,那就是 [bef+1,nxt] 里面的每个 x,fx=max(fx,nxt)。
那这个我们区间去最大我们可以用线段树来搞。
然后你上面那个 m∑i=1(yi−yi−1)fi 我们可以给区间赋一个权值为 yr−yl,每次赋值贡献要乘上这个东西。
但是最后你要的是区间求和,那我们似乎要用吉司机线段树?
其实不用,因为这个 fx 显然有着单调的性质,那我们直接二分出贡献的区间,然后直接变成区间赋值就好了。
时间复杂度是 nlog2n。
代码
#include<set>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#define ll long long
#define mo 1000000007
using namespace std;
const ll N = 2005;
ll n, k, L, x[N], y[N], xn, yn;
vector <pair<ll, ll> > cx[N];
vector <ll> cy[N];
ll ans;
struct node {
ll x, y, c;
}e[N];
multiset <ll> S, s[N];
ll nxt[N], R[N];
struct XD_tree {
ll f[N << 2], lzy[N << 2], maxn[N << 2], sz[N << 2];
void up(ll now) {
f[now] = (f[now << 1] + f[now << 1 | 1]) % mo;
maxn[now] = max(maxn[now << 1], maxn[now << 1 | 1]);
}
void downc(ll now, ll x) {
f[now] = sz[now] * x % mo;
maxn[now] = x; lzy[now] = x;
}
void down(ll now, ll l, ll r) {
ll mid = (l + r) >> 1;
if (lzy[now] != -1) {
downc(now << 1, lzy[now]); downc(now << 1 | 1, lzy[now]);
lzy[now] = -1;
}
}
ll find(ll now, ll l, ll r, ll k) {
if (l == r) return (maxn[now] > k) ? l : r + 1;
down(now, l, r); ll mid = (l + r) >> 1;
if (maxn[now << 1] > k) return find(now << 1, l, mid, k);
else return find(now << 1 | 1, mid + 1, r, k);
}
void change(ll now, ll l, ll r, ll L, ll R, ll va) {
if (L <= l && r <= R) {
downc(now, va); return ;
}
down(now, l, r); ll mid = (l + r) >> 1;
if (L <= mid) change(now << 1, l, mid, L, R, va);
if (mid < R) change(now << 1 | 1, mid + 1, r, L, R, va);
up(now);
}
void change_(ll L, ll R, ll va) {
if (L > R) return ; ll pl = min(R, find(1, 1, yn, va) - 1);
if (L <= pl) change(1, 1, yn, L, pl, va);
}
void build(ll now, ll l, ll r) {
lzy[now] = -1;
if (l == r) {
sz[now] = y[l] - y[l - 1]; maxn[now] = R[l]; f[now] = maxn[now] * sz[now] % mo; return ;
}
ll mid = (l + r) >> 1;
build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);
up(now); sz[now] = (sz[now << 1] + sz[now << 1 | 1]) % mo;
}
}T;
void work(ll l) {
for (ll i = 1; i <= yn; i++) cy[i].clear();
for (ll i = l; i <= xn; i++)
for (ll j = 0; j < cx[i].size(); j++)
cy[cx[i][j].first].push_back(cx[i][j].second);
S.clear();
for (ll i = 1; i <= k; i++) {
nxt[i] = yn + 1; S.insert(nxt[i]);
s[i].clear(); s[i].insert(0); s[i].insert(nxt[i]);
}
for (ll i = yn; i >= 1; i--) {
for (ll j = 0; j < cy[i].size(); j++) {
S.erase(S.find(nxt[cy[i][j]]));
nxt[cy[i][j]] = i;
S.insert(nxt[cy[i][j]]);
s[cy[i][j]].insert(i);
}
R[i] = y[*(--S.end())];
}
T.build(1, 1, yn);
for (ll r = xn; r >= l; r--) {
ll sum = (1ll * y[yn] * (L + 1) % mo - T.f[1] + mo) % mo;
(ans += sum * (x[r + 1] - x[r]) % mo * (x[l] - x[l - 1]) % mo) %= mo;
for (ll i = 0; i < cx[r].size(); i++) {
ll col = cx[r][i].second, Y = cx[r][i].first;
s[col].erase(s[col].find(Y));
ll bef = *(--s[col].lower_bound(Y));
ll nxt = *s[col].lower_bound(Y);
T.change_(bef + 1, Y, y[nxt]);
}
}
}
int main() {
scanf("%lld %lld %lld", &n, &k, &L);
for (ll i = 1; i <= n; i++) {
ll z; scanf("%lld %lld %lld", &x[i], &y[i], &z);
x[i]++; y[i]++; e[i] = (node){x[i], y[i], z};
}
sort(x + 1, x + n + 1); xn = unique(x + 1, x + n + 1) - x - 1; x[xn + 1] = L + 1;
sort(y + 1, y + n + 1); yn = unique(y + 1, y + n + 1) - y - 1; y[yn + 1] = L + 1;
for (ll i = 1; i <= n; i++) {
ll X = lower_bound(x + 1, x + xn + 1, e[i].x) - x;
ll Y = lower_bound(y + 1, y + yn + 1, e[i].y) - y;
cx[X].push_back(make_pair(Y, e[i].c));
}
for (ll i = 1; i <= xn; i++) work(i);
printf("%lld", ans);
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现