zoukankan      html  css  js  c++  java
  • [CSP校内集训]矩形面积交(树状数组)

    题意

    (n)个互不相交的矩形,再给(m)个询问,每次给一个矩形求它与这(n)个矩形的面积交

    思路

    自己写的太丑了导致DEBUG了一个半小时qwq

    一对矩形的交可以拆分成二维前缀和形式下的矩形的交,于是变成判断16次矩形的交(不想画图...只想口胡)

    这些矩形都有(x_0=0,y_0=0),即左下角为坐标原点,于是一个矩形可以只用右上角的坐标表示;

    对于一个询问的矩形((x,y))和另一个矩形((x_i,y_i)),它们的交为(min(x,x_i) imes min(y,y_i))

    (x)排序,分类讨论(yleq y_i)(y>y_i),用树状数组维护即可

    Code

    #include<bits/stdc++.h>
    #define N 500005
    #define int ll
    #define lowbit(x) ((x)&(-(x)))
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    int n,m,w,l,cnt0,cnt;
    ll sum[N],sumy[N],sumx[N],c[N];
    struct Matrix { int x,y,opt; } ma[N<<2];
    struct Query { int x,y,id,opt; ll ans; } q[N<<2];
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    void ad(int id,int opt,int x,int y)
    {
    	++cnt;
    	q[cnt].id=id; q[cnt].opt=opt;
    	q[cnt].x=x; q[cnt].y=y;	
    }
    void modify_1(int x,int val) { for(;x<N;x+=lowbit(x)) c[x]+=val; }
    void modify_2(int x,ll val) { for(;x<N;x+=lowbit(x)) sum[x]+=val; }
    void modify_3(int x,ll val) { for(;x<N;x+=lowbit(x)) sumy[x]+=val; }
    void modify_4(int x,ll val) { for(;x<N;x+=lowbit(x)) sumx[x]+=val; } 
    ll query_1(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=c[x]; return ret;}
    ll query_2(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sum[x]; return ret;}
    ll query_3(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sumy[x]; return ret;}
    ll query_4(int x) { ll ret=0; for(;x;x-=lowbit(x)) ret+=sumx[x]; return ret;} 
    void update(Matrix a)//加入矩阵a 
    {
    	modify_1(a.y,a.opt);
    	modify_2(a.y,a.opt*(a.x*a.y));
    	modify_3(a.y,a.opt*a.y);
    	modify_4(a.y,a.opt*a.x);
    }
    bool cmp1(Matrix a,Matrix b) { return a.x<b.x; }
    bool cmp2(Query a,Query b) { return a.x<b.x; }
    bool cmp3(Query a,Query b) { return a.id<b.id; }
    signed main()
    {
    	freopen("intersec.in","r",stdin);
    	freopen("intersec.out","w",stdout);
    	read(n);read(m);read(w);read(l);
    	for(int i=1;i<=n;++i)
    	{
    		int x[2],y[2];
    		read(x[0]);read(y[0]);
    		read(x[1]);read(y[1]);
    		ma[++cnt0]=(Matrix){x[1],y[1],1};
    		ma[++cnt0]=(Matrix){x[0],y[1],-1};
    		ma[++cnt0]=(Matrix){x[1],y[0],-1};
    		ma[++cnt0]=(Matrix){x[0],y[0],1};
    	}
    	for(int i=1;i<=m;++i)
    	{
    		int x[2],y[2];
    		read(x[0]);read(y[0]);
    		read(x[1]);read(y[1]);
    		ad(i,1,x[1],y[1]);
    		ad(i,-1,x[0],y[1]);
    		ad(i,-1,x[1],y[0]);
    		ad(i,1,x[0],y[0]);
    	}
    	sort(ma+1,ma+cnt0+1,cmp1);
    	sort(q+1,q+cnt+1,cmp2);
    	int L=0;//加入了L个矩阵 
    	for(int i=1;i<=cnt;++i)//处理第i个询问矩阵 
    	{
    		if(q[i].x==0||q[i].y==0) continue;
    		while(L<cnt0&&ma[L+1].x<=q[i].x)
    		{
    			++L;
    			if(ma[L].x>0&&ma[L].y>0) update(ma[L]);
    		}
    		q[i].ans+=(query_2(q[i].y) + q[i].y*(query_4(N-1)-query_4(q[i].y)));
    	}
    	
    	memset(c,0,sizeof(c));
    	memset(sum,0,sizeof(sum));
    	memset(sumx,0,sizeof(sumx));
    	memset(sumy,0,sizeof(sumy));
    	int R=cnt0+1;
    	for(int i=cnt;i>=1;--i)
    	{
    		if(q[i].x==0||q[i].y==0) continue;
    		while(R>1&&ma[R-1].x>q[i].x)
    		{
    			--R;
    			if(ma[R].x>0&&ma[R].y>0) update(ma[R]);
    		}
    		q[i].ans+=q[i].x * (query_3(q[i].y) + (query_1(N-1)-query_1(q[i].y))*q[i].y);
    	}
    	sort(q+1,q+cnt+1,cmp3);
    	for(int i=1;i<=cnt;i+=4)
    	{
    		ll ans=0;
    		for(int j=0;j<4;++j) ans+=q[i+j].opt*q[i+j].ans;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux crontab 定时使用方法
    crontab 选择编辑器 select-editor
    设置定时任务为每天凌晨2点执行和每小时执行一次
    性能测试工具--SIEGE安装及使用简介 siege压力测试
    Vue基础
    使用 supervisor 管理进程
    长按listview弹出选项列表对话框
    左右滑动弹窗之间短信内容区域来显示上一条和下一条短信
    在开机广播中启动服务
    Android spinner 样式及其使用详解
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11782389.html
Copyright © 2011-2022 走看看