1 条题解
-
0
自动搬运
来自洛谷,原作者为

zifanwang
RP++搬运于
2025-08-24 22:38:25,当前版本为作者最后更新于2022-10-27 21:30:08,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先对于每一个矩形,若 ,就将 均乘上 再交换,对于 也做同样的操作。
我们建立一个操作序列
a[0~1000],和一个数组 ,每一个操作用 表示,就是在 内把所有 到 的位置加上 。我们再定义一种新的操作 ,表示对于每一个 都在
a[i]处插入一个操作 。我们定义一种行为 ,表示执行:
- 若 ,就执行三个操作操作
- 若 ,就执行操作
- 若 ,就执行两个操作
下面对于每一个矩形的 进行分类:
- 若 ,执行行为 $\{-y_1,x_1,x_2,1\},\{y_2,x_1,x_2,1\},\{0,x_1,x_2,-1\}$
- 若 ,执行行为
- 若 ,执行行为
因为询问的时间是单调递增的,可以记录一个时间 ,表示当前是 时刻,初始化 。对于每一个询问 ,重复下面的操作直到 :
- 将 ,然后执行
a[t]的所有操作。
最后的答案就对于每一个 , 数组内第 个位置对应的值的和,可以用树状数组维护 。但是这只能过掉 的数据。
正解
我们发现要执行的操作 的数量是不多的。
再经过仔细思考,可以发现 时刻的答案就是对于所有 , 的和。详细的原因可以看看题解的末尾。
我们先不执行这些操作,把这些操作插入到一个集合 ,然后维护四个值
sum,add,ans,addans:-
sum表示所有 的操作 的 的和。 -
add表示 每怎加 时sum要增加的值,也就是所有 的操作 的 的和。 -
ans表示所有 的操作 对答案的贡献。 -
addans表示 每怎加 时ans要增加的值,也就是所有 的操作 的 的和。
我们建立一个 数组,对于每一个操作 在
dl[x+1]处插入。当 每次增加 时,枚举所有
dl[t]内的操作 :-
若此操作已经在集合 内被删除了(也就是在这次询问之前 ),就把
addans减去 。 -
若此操作还在集合 内(也就是在这次询问之前 ),就把
add减去 。
直到 时 才停止增加,下面再更新集合 。枚举所有满足 的操作 :
-
若 ,说明此操作还在未在上面的
dl数组中被访问过,此时sum要减去 ,add减去 ,ans加上 ,addans加上 。 -
若 ,把
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; }问题:为什么 时刻的答案就是对于所有 , 的和。
题目要求的就是一个左下角为 ,右上角为 的大矩形和一些其他的矩形的交的面积之和。
因为最终的答案是所有 时的 数组内的第 到 个位置对应的值的总和,操作 就可以转化成一个左下角是 ,右上角是 ,权值为 的矩形。
答案就是一个左下角是 ,右上角是 的大矩形和每一个 对应的矩形的交的面积乘以 的和。
- 1
信息
- ID
- 7673
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者