Codeforces Round #666(未完)

Codeforces Round #666

前言

感觉我补题速度好慢。。
上大学后,因为不存在停课,能分给acm的时间还是挺少的。。
然而我效率总是提不上来。。唉。。。。

A to C 略

D Rainbow Rectangles

题意

一个边长为\(L\)的正方形网格上,有\(n\)颗糖,第\(i\)颗糖所在位置为\((xi+0.5,yi+0.5)\),每颗糖都有颜色,颜色一共有\(K\)种,问有多少端点在整点上的矩形包含了所有的颜色,即在这种矩阵中,每种颜色的糖至少出现一次。\(0\leq K \leq n \leq 2000,1\leq L\leq {10}^{9}\) 。

题解

首先肯定离散化。
如果是一维上的话,我们用双指针就是\(O(n)\)的做法。
转换到两维平面上,显然枚举左右端点,然后中间用一维的方法就得到了\(O(n^3)\)的做法。
然而这肯定不行。。考虑怎么压掉一个n。
我们考虑在枚举左右端点时,能否快速得到中间部分的答案。
左端点肯定是从左向右,这时候右端点有两种枚举方法:从左向右,从右向左。
向右的话我们需要维护增加的点,新增的点的贡献很难算。。
向左的话,我们需要维护删点的操作。我们可以维护每个点颜色相同的左边高度比它高的最低点u,以及比它低的最高点d。(这里要用到链表)
然后删点时我们用u来更新d上方的所有点,这个操作可以用线段树。然后就能快速统计答案了。。。

\(Code\)

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e3+10;
const LL mod=1e9+7;
int read(){
    int 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;
}
void print(LL x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
struct link{
	int L[N],R[N];
	void del(int x){
		R[L[x]]=R[x];
		L[R[x]]=L[x];
	}
}S,s;
int n,K,L;
struct P{int x,y,c,ny;}a[N];
bool cmpx(P x,P y){return x.x<y.x;}
bool cmpy(P x,P y){return x.y<y.y;}
int sy[N],las[N];

#define ls ch[0]
#define rs ch[1]

int col[N];
int f[N],t[N];


struct node{
	int l,r,mid;
	int sum,mn,mx,lazy;
	node *ch[2];
	node(int x,int y):l(x),r(y),mid(l+r>>1),sum(0){
		if(x<y){
			ls=new node(x,mid);
			rs=new node(mid+1,y);
		}
		else ls=rs=NULL;
	}
	void update(int c){
		sum=1ll*(sy[r]-sy[l-1])*c%mod;
		lazy=mn=mx=c;
	}
	void pushup(){
		sum=(ls->sum+rs->sum)%mod;
		mn=min(ls->mn,rs->mn);
		mx=max(ls->mx,rs->mx);
	}
	void init(){
		if(l==r){update(f[l]);return;}
		ls->init();rs->init();lazy=0;
		pushup();
	}
	void change(int x,int c){
		if(mn>=c) return;
		if(mx<=c&&l==x){
			update(c);
			return;
		} 
		if(lazy){
			if(ls) {
				ls->update(lazy);
				rs->update(lazy);
			}
			lazy=0;
		}
		if(x<=mid) ls->change(x,c);
		rs->change(max(mid+1,x),c);
		pushup();
	}
}*root=NULL;

LL ans=0;

int main(){
	scanf("%d%d%d",&n,&K,&L);
	for(int i=1;i<=n;++i){
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
	}
	sort(a+1,a+1+n,cmpy);
	a[0].x=a[0].y=-1;a[n+1].x=a[n+1].y=L;
	for(int i=0;i<=n+1;++i) {sy[i]=a[i].y;a[i].ny=i;}
	for(int i=1;i<=n;++i){
		int &it=las[a[i].c];
		if(it) {s.R[it]=i;s.L[i]=it;}
		s.R[i]=n+1;it=i;
	}
	sort(a+1,a+1+n,cmpx);
	root=new node(1,n);
//	cout<<"y"<<endl;
	for(int i=1;i<=n;++i){
		//cout<<i<<endl;
		if(a[i].x!=a[i-1].x){
			for(int j=0;j<i;++j) col[a[j].ny]=0;
			for(int j=i;j<=n;++j) col[a[j].ny]=a[j].c;
			for(int l=1,r=1,tot=0;l<=n;++l){
				for(;r<=n&&tot<K;++r){
					if(col[r]&&!t[col[r]]) ++tot;
					t[col[r]]++;
				} 
				f[l]=(tot<K?L:sy[r-1]);
				--t[col[l]];
				if(col[l]&&!t[col[l]]) --tot;
			}
			root->init();S=s;
			for(int j=n;j>=1;j--){
				ans+=1ll*(1ll*(sy[n]+1)*L%mod-root->sum+mod)%mod*(a[j+1].x-a[j].x)%mod*(a[i].x-a[i-1].x)%mod;
				int p=a[j].ny; 
				root->change(S.L[p]+1,sy[S.R[p]]); 
				S.del(p);
			}
		}
		s.del(a[i].ny); 
	}
	ans=(ans%mod+mod)%mod;
	cout<<ans<<endl;
	return 0;
}

E Distance Matching

还没写QAQ

上一篇:Codeforces Round #666 (Div. 1)


下一篇:基本数据类型第一篇