bzoj5366 [Lydsy1805月赛]代码派对(容斥+差分+二维前缀和)

给定n个矩形,问至少覆盖了一个公共点的三元组(i,j,k)(i< j< k)有多少个。
矩形的交还是矩形。我们先差分+二维前缀和算出每一个位置被覆盖的次数 bij b i j ,答案就是 C3bij ∑ C b i j 3
但是这样会算重。我们考虑三个矩形i,j,k,它们的交也是一个矩形,在这个矩形的每一个位置上我们都计算了这个三元组的贡献。我们减去同时覆盖了(i-1,j),(i,j)贡献,再减去同时覆盖了(i,j-1),(i,j)的贡献。可以发现对于同时覆盖了(i-1,j-1),(i,j)的三元组我们减了两次贡献,所以我们还要加回同时覆盖了(i-1,j-1),(i,j)的贡献。这样每一个合法的三元组都只会在它的交的矩形的左上角被计算一次贡献。
如何计算同时覆盖了(i-1,j),(i,j)的贡献呢?我们把所有矩形都删掉最上面一行即可。这样如果三个矩形还是在(i,j)有交,那么一定在(i-1,j)也有交。
剩下的同理。
复杂度 O(n+m2) O ( n + m 2 )

#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,b1[1010][1010],b2[1010][1010],b3[1010][1010],b4[1010][1010];
inline ll calc(ll x){return  x*(x-1)*(x-2)/6;}
int main(){
//  freopen("a.in","r",stdin);
    int tst=read();
    while(tst--){
        n=read();ll ans=0;memset(b1,0,sizeof(b1));memset(b2,0,sizeof(b2));
        memset(b3,0,sizeof(b3));memset(b4,0,sizeof(b4));
        for(int i=1;i<=n;++i){
            int x1=read(),y1=read(),x2=read(),y2=read();
            b1[x1][y1]++;b1[x1][y2+1]--;
            b1[x2+1][y1]--;b1[x2+1][y2+1]++;
            b2[x1+1][y1]++;b2[x1+1][y2+1]--;
            b2[x2+1][y1]--;b2[x2+1][y2+1]++;
            b3[x1][y1+1]++;b3[x1][y2+1]--;
            b3[x2+1][y1+1]--;b3[x2+1][y2+1]++;
            b4[x1+1][y1+1]++;b4[x1+1][y2+1]--;
            b4[x2+1][y1+1]--;b4[x2+1][y2+1]++;
        }for(int i=1;i<=1000;++i)
            for(int j=1;j<=1000;++j){
                b1[i][j]+=b1[i-1][j]+b1[i][j-1]-b1[i-1][j-1];
                b2[i][j]+=b2[i-1][j]+b2[i][j-1]-b2[i-1][j-1];
                b3[i][j]+=b3[i-1][j]+b3[i][j-1]-b3[i-1][j-1];
                b4[i][j]+=b4[i-1][j]+b4[i][j-1]-b4[i-1][j-1];
                ans+=calc(b1[i][j])-calc(b2[i][j])-calc(b3[i][j])+calc(b4[i][j]);
            }
        printf("%lld\n",ans);
    }return 0;
}

你可能感兴趣的:(bzoj,容斥原理,差分)