[COI2009] PLAHTE 题解

首先对于每一个矩形,若 \(x_2<0\),就将 \(x_1,x_2\) 均乘上 \(-1\) 再交换,对于 \(y_1,y_2\) 也做同样的操作。

我们建立一个操作序列 a[0~1000],和一个数组 \(d\),每一个操作用 \((x,y)\) 表示,就是在 \(d\) 内把所有 \(0\)\(x\) 的位置加上 \(y\)

我们再定义一种新的操作 \([x,y,z]\),表示对于每一个 \(0\le i\le x\) 都在 a[i] 处插入一个操作 \((y,z)\)

我们定义一种行为 \(\{i,x_1,x_2,z\}\),表示执行:

  • \(x_1<0\),就执行三个操作操作 \([i,-x_1,z],[i,x_2,z],[i,0,-z]\)
  • \(x_1=0\),就执行操作 \([i,x_2,z]\)
  • \(x_1>0\),就执行两个操作 \([i,x_2,z],[i,x_1-1,-z]\)

下面对于每一个矩形的 \(y_1,y_2\) 进行分类:

  • \(y_1<0\),执行行为 \(\{-y_1,x_1,x_2,1\},\{y_2,x_1,x_2,1\},\{0,x_1,x_2,-1\}\)
  • \(y_1=0\),执行行为 \(\{y_2,x_1,x_2,1\}\)
  • \(y_1>0\),执行行为 \(\{y_2,x_1,x_2,1\},\{y_1-1,x_1,x_2,-1\}\)

因为询问的时间是单调递增的,可以记录一个时间 \(t\),表示当前是 \(t\) 时刻,初始化 \(t=-1\)。对于每一个询问 \(k\),重复下面的操作直到 \(t=k\)

  • \(t+1\),然后执行 a[t] 的所有操作。

最后的答案就对于每一个 \(0\le i\le k\)\(d\) 数组内第 \(i\) 个位置对应的值的和,可以用树状数组维护 \(d\)。但是这只能过掉 \(|y_1|,|y_2|\le 1000\) 的数据。

正解

我们发现要执行的操作 \([x,y,z]\) 的数量是不多的。

再经过仔细思考,可以发现 \(t\) 时刻的答案就是对于所有 \([x,y,z]\)\((\min(x,t)+1)(\min(y,t)+1)\times z\) 的和。详细的原因可以看看题解的末尾。

我们先不执行这些操作,把这些操作插入到一个集合 \(S\),然后维护四个值 sum,add,ans,addans

  • sum 表示所有 \(y>t\) 的操作 \([x,y,z]\)\(z\times(\min(x,t)+1)\) 的和。

  • add 表示 \(t\) 每怎加 \(1\)sum 要增加的值,也就是所有 \(y>t\land x>t\) 的操作 \([x,y,z]\)\(z\) 的和。

  • ans 表示所有 \(y\le t\) 的操作 \([x,y,z]\) 对答案的贡献。

  • addans 表示 \(t\) 每怎加 \(1\)ans 要增加的值,也就是所有 \(y\le t\land x>t\) 的操作 \([x,y,z]\)\(z\times(y+1)\) 的和。

我们建立一个 \(dl\) 数组,对于每一个操作 \([x,y,z]\)dl[x+1] 处插入。

\(t\) 每次增加 \(1\) 时,枚举所有 dl[t] 内的操作 \([x,y,z]\)

  • 若此操作已经在集合 \(S\) 内被删除了(也就是在这次询问之前 \(y\le t\)),就把 addans 减去 \(z\times(y+1)\)

  • 若此操作还在集合 \(S\) 内(也就是在这次询问之前 \(y>t\)),就把 add 减去 \(z\)

直到 \(t=k\)\(t\) 才停止增加,下面再更新集合 \(S\)。枚举所有满足 \(y\le k\) 的操作 \([x,y,z]\)

  • \(x\ge k\),说明此操作还在未在上面的 dl 数组中被访问过,此时 sum 要减去 \(z\times(k+1)\)add 减去 \(z\)ans 加上 \(z\times (k+1)(y+1)\)addans 加上 \(z\times (y+1)\)

  • \(x<k\),把 sum 减去 \(z\times (x+1)\)ans 加上 \(z\times (x+1)(y+1)\)

最终的答案就是 \((t+1)\times sum+ans\)

代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 1000003
#define md 1000000007
#define pb push_back
#define mkp make_pair
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
inline int read(){
	int x=0;bool flag=true;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();}
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return flag?x:-x;
}
struct node{
	int x,y,z;
};
inline bool operator<(node x,node y){
	return x.y!=y.y?x.y<y.y:x.x!=y.x?x.x<y.x:x.z<y.z;
}
int n,m,t=-1;
vector<node>dl[mxn];
multiset<node>s;
ll sum,add,ans,ads;
void puta(int x,int y,int z){
	add+=z;
	s.insert({x,y,z});
	dl[x+1].pb({x,y,z});
}
void ins(int x,int l,int r,int y){
	if(l<0){
		puta(x,-l,y);
		puta(x,r,y);
		puta(x,0,-y);
	}else if(l==0){
		puta(x,r,y);
	}else{
		puta(x,r,y);
		puta(x,l-1,-y);
	}
}
signed main(){
	n=read();
	for(int i=0,x1,x2,y1,y2;i<n;++i){
		x1=read(),y1=read(),x2=read(),y2=read();
		if(x1<0&&x2<0){
			swap(x1,x2);
			x1=-x1,x2=-x2;
		}
		if(y1<0&&y2<0){
			swap(y1,y2);
			y1=-y1,y2=-y2;
		}
		if(y1<0){
			ins(-y1,x1,x2,1);
			ins(y2,x1,x2,1);
			ins(0,x1,x2,-1);
		}else if(y1==0){
			ins(y2,x1,x2,1);
		}else{
			ins(y2,x1,x2,1);
			ins(y1-1,x1,x2,-1);
		} 
	}
	m=read();
	int x;
	while(m--){
		x=read();
		while(t<x){
			t++;
			for(node i:dl[t]){
				auto it=s.find(i);
				if(it==s.end())ads-=i.z*(i.y+1ll);
				else add-=i.z;
			}
			sum+=add;
			ans+=ads;
		}
		while(s.size()&&(s.begin()->y)<=x){
			node i=*s.begin();s.erase(s.begin());
			if(i.x>=x){
				sum-=i.z*(x+1ll);
				add-=i.z;
				ans+=i.z*(i.y+1ll)*(x+1ll);
				ads+=i.z*(i.y+1ll);
			}else{
				sum-=i.z*(i.x+1ll);
				ans+=(i.x+1ll)*(i.y+1ll)*i.z;
			}
		}
		printf("%lld\n",sum*(x+1ll)+ans);
	}
	return 0;
}

问题:为什么 \(t\) 时刻的答案就是对于所有 \([x,y,z]\)\((\min(x,t)+1)(\min(y,t)+1)\times z\) 的和。

题目要求的就是一个左下角为 \((-k,-k)\),右上角为 \((k,k)\) 的大矩形和一些其他的矩形的交的面积之和。

因为最终的答案是所有 \(t\le k\) 时的 \(d\) 数组内的第 \(0\)\(i\) 个位置对应的值的总和,操作 \([x,y,z]\) 就可以转化成一个左下角是 \((0,0)\),右上角是 \((x,y)\),权值为 \(z\) 的矩形。

答案就是一个左下角是 \((0,0)\),右上角是 \((k,k)\) 的大矩形和每一个 \([x,y,z]\) 对应的矩形的交的面积乘以 \(z\) 的和。

posted @ 2024-02-27 22:04  zifanwang  阅读(3)  评论(0编辑  收藏  举报