[COI2009] PLAHTE 题解
首先对于每一个矩形,若
我们建立一个操作序列 a[0~1000],和一个数组
我们再定义一种新的操作 a[i] 处插入一个操作
我们定义一种行为
- 若
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<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+1 ,然后执行a[t]的所有操作。
最后的答案就对于每一个
正解
我们发现要执行的操作
再经过仔细思考,可以发现
我们先不执行这些操作,把这些操作插入到一个集合 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+1] 处插入。
当 dl[t] 内的操作
-
若此操作已经在集合
S 内被删除了(也就是在这次询问之前y\le t ),就把addans减去z\times(y+1) 。 -
若此操作还在集合
S 内(也就是在这次询问之前y>t ),就把add减去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) 。
最终的答案就是
代码:
#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;
}
问题:为什么
题目要求的就是一个左下角为
因为最终的答案是所有
答案就是一个左下角是