← 返回题解列表

P1073 相见欢 官方题解

【部分分:测试点 1∼31\sim 31∼3】

  • 本题为原创题。
  • 这一档中坐标范围很小。把平面划分成整数单位方格,枚举每个小矩形覆盖的全部方格,并记录每个方格的覆盖次数。
  • 设全部小矩形的外接矩形为 RR。当且仅当 RR 内的每个单位方格恰好被覆盖一次,且 RR 外没有方格被覆盖时,答案为 Yes
  • 设坐标范围宽度为 BB,时间复杂度为 O(nB2)\mathcal O(nB^2),空间复杂度为 O(B2)\mathcal O(B^2)

【部分分:测试点 4∼74\sim 74∼7】

  • 两个矩形的内部相交,当且仅当它们在横轴、纵轴上的开区间投影都相交。
  • 对矩形 A,BA,B,分别记横坐标区间为 (lA,rA),(lB,rB)(l_A,r_A),(l_B,r_B),纵坐标区间为 (dA,uA),(dB,uB)(d_A,u_A),(d_B,u_B)。内部相交等价于
max(lA,lB)<min(rA,rB),max(dA,dB)<min(uA,uB).\begin{aligned} \max(l_A,l_B)&<\min(r_A,r_B),\\ \max(d_A,d_B)&<\min(u_A,u_B). \end{aligned}
  • 枚举每一对矩形,若存在内部相交则直接判为不合法。否则只需继续检查是否存在遗漏。

  • 记小矩形面积和为 SS,外接矩形面积为 SRS_R。已经确认内部两两不交时,小矩形并集的面积恰为 SS

  • 所有小矩形都位于 RR 内,因此 SSRS\leq S_R。若 S=SRS=S_R,并集与 RR 的面积相同,便不存在正面积的空缺。

  • 所有边界均平行于坐标轴,若存在未覆盖点,则其附近一定含有一个未覆盖的小矩形区域,面积为正,与 S=SRS=S_R 矛盾。

  • 时间复杂度为 O(n2)\mathcal O(n^2),空间复杂度为 O(1)\mathcal O(1)

【部分分:测试点 8∼118\sim 118∼11】

  • 将所有矩形的左右边界离散化为 X1<X2<<XpX_1<X_2<\cdots<X_p,上下边界离散化为 Y1<Y2<<YqY_1<Y_2<\cdots<Y_q
  • 任意两条相邻横坐标与相邻纵坐标围成一个最小矩形。原矩形对这些最小矩形的覆盖情况是完整的,不会从中间切开它们。
  • 对离散网格做二维差分。每个原矩形只产生四次修改,恢复前缀和后即可得到每个最小矩形的覆盖次数。
  • 检查外接矩形内覆盖次数是否都为 11。时间复杂度为 O(n+pq)\mathcal O(n+pq),空间复杂度为 O(pq)\mathcal O(pq)

【部分分:测试点 12∼1512\sim 1512∼15】

  • 特殊性质已经保证任意两个小矩形的内部互不相交,重叠问题不再需要检查。
  • 计算外接矩形 RR 与面积和 SS。若 S=SRS=S_R,根据前面的面积论证,不可能再存在空缺。
  • 因而本档只需一次扫描,时间复杂度为 O(n)\mathcal O(n),空间复杂度为 O(1)\mathcal O(1)
  • 完整数据中不能预先排除重叠。面积相等仍然不够,因为一块重叠区域和一块等面积空缺会相互抵消。

【正解】

  • 面积负责检查总量。还需要一个条件检查局部边界是否能严丝合缝地消失。

  • 对每个小矩形的四个角点进行异或式统计。角点第一次出现时放入集合,第二次出现时从集合删除,之后继续交替。

  • 换句话说,集合中只保存出现次数为奇数的角点。

  • 若小矩形恰好拼成外接矩形,内部角点与外接边上的非顶点都会成对出现,最终只剩外接矩形的四个顶点。

  • 记外接矩形四角组成的集合为

CR={(xmin,ymin),(xmin,ymax),(xmax,ymin),(xmax,ymax)}.C_R=\{(x_{\min},y_{\min}),(x_{\min},y_{\max}), (x_{\max},y_{\min}),(x_{\max},y_{\max})\}.
  • 完整判定条件为
S=SRC=CR,S=S_R \qquad\text{且}\qquad C=C_R,

其中 CC 是所有小矩形角点异或后的集合。

  • 两个条件缺一不可。只检查面积无法发现“重叠抵消空缺”,只检查角点也无法排除某些重复覆盖。

  • 下面说明充分性。把所有小矩形的边界叠加在一起。若内部存在空缺或重叠区域,那么该异常区域的边界由若干条水平、竖直线段组成。

  • 异常边界的转折点会使某个非外接角点出现奇数次,或者使外接矩形的某个角点奇偶性错误,因此无法得到 C=CRC=C_R

  • 角点条件排除了局部边界异常,面积条件又保证总覆盖量等于外接矩形面积,所以覆盖既没有遗漏,也没有重叠。

  • 使用有序集合时,时间复杂度为 O(nlogn)\mathcal O(n\log n),空间复杂度为 O(n)\mathcal O(n)。使用哈希集合可以得到期望 O(n)\mathcal O(n) 时间。

【参考代码】

/*Author:EhundateghDate:2026/8/26Name:reunion.cppYou steal,I kill.*/#include <set>#include <cstdio>#include <algorithm>using namespace std; int T,n; void Change(set<pair<int,int> > &S,int x,int y){    pair<int,int> Now={x,y};    if(S.find(Now)==S.end()) S.insert(Now);    else S.erase(Now);} void Solve(){    int x1,y1,x2,y2;    int MinX=0x3f3f3f3f,MinY=0x3f3f3f3f;    int MaxX=-0x3f3f3f3f,MaxY=-0x3f3f3f3f;    long long Sum=0;    set<pair<int,int> > S;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);        MinX=min(MinX,x1);MinY=min(MinY,y1);        MaxX=max(MaxX,x2);MaxY=max(MaxY,y2);        Sum+=1ll*(x2-x1)*(y2-y1);        Change(S,x1,y1);Change(S,x1,y2);        Change(S,x2,y1);Change(S,x2,y2);    }    bool Tag=Sum==1ll*(MaxX-MinX)*(MaxY-MinY)&&S.size()==4;    Tag&=S.count({MinX,MinY})&&S.count({MinX,MaxY});    Tag&=S.count({MaxX,MinY})&&S.count({MaxX,MaxY});    puts(Tag?"Yes":"No");} int main(){    int c;    scanf("%d%d",&c,&T);    while(T-->0) Solve();    return 0;}