1 条题解

  • 0
    @ 2025-8-24 22:38:25

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zifanwang
    RP++

    搬运于2025-08-24 22:38:25,当前版本为作者最后更新于2022-10-27 21:30:08,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先对于每一个矩形,若 x2<0x_2<0,就将 x1,x2x_1,x_2 均乘上 1-1 再交换,对于 y1,y2y_1,y_2 也做同样的操作。

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

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

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

    • x1<0x_1<0,就执行三个操作操作 [i,x1,z],[i,x2,z],[i,0,z][i,-x_1,z],[i,x_2,z],[i,0,-z]
    • x1=0x_1=0,就执行操作 [i,x2,z][i,x_2,z]
    • x1>0x_1>0,就执行两个操作 [i,x2,z],[i,x11,z][i,x_2,z],[i,x_1-1,-z]

    下面对于每一个矩形的 y1,y2y_1,y_2 进行分类:

    • y1<0y_1<0,执行行为 $\{-y_1,x_1,x_2,1\},\{y_2,x_1,x_2,1\},\{0,x_1,x_2,-1\}$
    • y1=0y_1=0,执行行为 {y2,x1,x2,1}\{y_2,x_1,x_2,1\}
    • y1>0y_1>0,执行行为 {y2,x1,x2,1},{y11,x1,x2,1}\{y_2,x_1,x_2,1\},\{y_1-1,x_1,x_2,-1\}

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

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

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

    正解

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

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

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

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

    • add 表示 tt 每怎加 11sum 要增加的值,也就是所有 y>tx>ty>t\land x>t 的操作 [x,y,z][x,y,z]zz 的和。

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

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

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

    tt 每次增加 11 时,枚举所有 dl[t] 内的操作 [x,y,z][x,y,z]

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

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

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

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

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

    最终的答案就是 (t+1)×sum+ans(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;
    }
    

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

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

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

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

    • 1

    信息

    ID
    7673
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者