一、题目
二、解法
考虑如果这个问题放在一维上是具有单调性的,尺取法可以做到 (O(n))
我们可以通过枚举上下边界把它变成一维问题,从左往右扫可以做到 (O(n^3))
我们考虑优化掉边界枚举的过程,也就是我们固定上边界,移动下边界。设 (f_l) 表示在上下边界中 (y=l) 的最小右端点,我们需要在移动边界时动态维护这东西。
如果我们把下边界从上往下扫,那么会产生一个增加点的问题,但是增加点对于 (f) 的影响是不好考虑的,因为我们不知道它是怎么变小的。
考虑把下边界从下往上扫,那么会产生一个删除点的问题,设这个点的同色前驱(定义为边界内 (y) 比它不比他大的最大点)为 (pre),后继(定义类似)为 (nxt),那么会把 (jin(pre,i]) 的 (f_jleftarrowmax(f_j,nxt))
因为 (f) 具有单调性,所以可以用线段树转化为维护区间赋值,时间复杂度 (O(n^2log n))
离散化的部分真的不好讲,这个东西需要你去实现然后自行体会,可以参考优美实现:
三、总结
为什么二维问题我只会扫描线?其实常规模型是很多的。比如计算方形可以使用二维 ( t st) 表;计算矩形可以考虑枚举边界转一维问题;或者是中线分治,考虑过中线的矩形(说实话这个我现在不是很会)
不一定只有增加好做,比如这题就是删除好做,你主要看怎么做会产生易于维护的限制,这才是数据结构题的关键。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 2005;
const int N = 8005;
const int MOD = 1e9+7;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,f[M],c[M],ys[M],ls[M],col[M];
int ans,sum[N],mi[N],mx[N],tag[N],vis[M];
struct table
{
int l[M],r[M];
void del(int x) {l[r[x]]=l[x];r[l[x]]=r[x];}
}nl,li;
struct node {int x,y,c,id;}a[M];
bool cmpx(node a,node b) {return a.x<b.x;}
bool cmpy(node a,node b) {return a.y<b.y;}
void fuck(int i,int l,int r,int c)
{
mi[i]=mx[i]=tag[i]=c;
sum[i]=(ys[r]-ys[l-1])*c;
}
void down(int i,int l,int r)
{
if(!tag[i]) return ;
int mid=(l+r)>>1;
fuck(i<<1,l,mid,tag[i]);
fuck(i<<1|1,mid+1,r,tag[i]);
tag[i]=0;
}
void up(int i)
{
mx[i]=max(mx[i<<1],mx[i<<1|1]);
mi[i]=min(mi[i<<1],mi[i<<1|1]);
sum[i]=sum[i<<1]+sum[i<<1|1];
}
void build(int i,int l,int r)
{
tag[i]=0;
if(l==r)
{
fuck(i,l,l,f[l]);
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
void add(int i,int l,int r,int L,int c)
{
if(L>r || mi[i]>=c) return ;
if(L<=l && mx[i]<=c)
{
fuck(i,l,r,c);
return ;
}
int mid=(l+r)>>1;down(i,l,r);
add(i<<1,l,mid,L,c);
add(i<<1|1,mid+1,r,L,c);
up(i);
}
signed main()
{
n=read();k=read();m=read();
for(int i=1;i<=n;i++)
a[i].x=read(),a[i].y=read(),a[i].c=read();
sort(a+1,a+1+n,cmpy);
a[0].x=a[0].y=-1;a[n+1].x=a[n+1].y=m;
for(int i=0;i<=n+1;i++) ys[i]=a[i].y,a[i].id=i;
for(int i=1;i<=n;i++)
{
int l=ls[a[i].c];ls[a[i].c]=i;
nl.r[l]=i;nl.l[i]=l;nl.r[i]=n+1;
}
sort(a+1,a+1+n,cmpx);
for(int i=1;i<=n;nl.del(a[i].id),i++)
if(a[i].x^a[i-1].x)
{
for(int j=1;j<=k;j++) vis[j]=0;
for(int j=1;j<i;j++) c[a[j].id]=0;
for(int j=i;j<=n;j++) c[a[j].id]=a[j].c;
for(int l=1,r=1,tot=0;l<=n;l++)
{
for(;tot<k && r<=n;r++) if(c[r])
vis[c[r]]++,tot+=(vis[c[r]]==1);
f[l]=(tot<k)?m:ys[r-1];
if(c[l]) vis[c[l]]--,tot-=!vis[c[l]];
}
build(1,1,n);li=nl;
for(int j=n;j>=i;j--)
{
ans+=((ys[n]+1)*m-sum[1])%MOD*
(a[i].x-a[i-1].x)%MOD
*(a[j+1].x-a[j].x)%MOD,ans%=MOD;
int x=a[j].id,l=li.l[x],r=li.r[x];
add(1,1,n,l+1,ys[r]);li.del(x);
}
}
printf("%lld
",ans);
}