题目大意
在坐标系里面给定了N个矩形,有M次询问,每次询问输入一个t,询问的是从(0,0)到(t,t)范围内的矩形的面积(重叠也算,不是矩形面积并)
解题思路
这道题很容易让人联想到二维的做法,但是我们一看数据范围,发现是20W,明显无法满足空间限制,那么应该怎么办呢?
首先,矩形是无更新的,这给我们了非常大的空间,那么我们就可以想办法得到每一个位置的函数表达式
既然只有一个t是变元,我们可以假定t是自变量,既然是面积,一定是一个二次函数的模型
假设S=a*t^2+b*t+c,那么我们可以用三个树状数组(或线段树)维护每一个位置的啊a,b和c,我们要求的不是矩形面积并,便可以单个矩形考虑,这样就分出来三种情况
给定范围和矩形部分相交,完全含住矩形和有一条边和矩形一条边重合,由于范围是正方形,我们便需要考虑矩形的点的x坐标和y坐标的关系。
具体的就是如果x2<y2就需要考虑竖相交的诸多情况,如果x2>y2就需要考虑竖相交的诸多情况
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int maxn = (int)2e5 + 10;
struct Bitarray{
LL T[maxn];
int lowbit(int x){return x & (-x);}
void clear(){memset(T, 0, sizeof(T));}
void add(int st, int ed, LL val){
for (int i = st; i < maxn; i += lowbit(i)) T[i] += val;
for (int i = ed + 1; i < maxn; i += lowbit(i)) T[i] -= val;
}
LL query(int pos){
LL sum = 0;
for (int i = pos; i > 0; i -= lowbit(i)) sum += T[i];
return sum;
}
}A, B, C;
void fun(int st, int ed, LL a, LL b, LL c){
A.add(st, ed, a);
B.add(st, ed, b);
C.add(st, ed, c);
}
int n, m;
void solve(){
A.clear(); B.clear(); C.clear();
scanf("%d", &n);
LL x1, x2, y1, y2;
for (int i = 0; i < n; i++){
scanf("%I64d%I64d%I64d%I64d", &x1, &y1, &x2, &y2);
if (max(x1, y1) < min(x2, y2))
fun(max(x1, y1), min(x2, y2), 1, -(x1 + y1), x1 * y1);
if (x2 < y2) fun(max(x2, y1) + 1, y2, 0, -x1 + x2, y1 * (x1 - x2));
if (y2 < x2) fun(max(y2, x1) + 1, x2, 0, -y1 + y2, x1 * (y1 - y2));
fun(max(x2, y2) + 1, maxn, 0, 0, (x2 - x1) * (y2 - y1));
}
scanf("%d", &m);
while(m--){
LL t;
scanf("%I64d", &t);
LL ans = 0;
ans += A.query(t) * t * t;
ans += B.query(t) * t;
ans += C.query(t);
printf("%I64d\n", ans);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "rt", stdin);
#endif
int cs; cin >> cs;
while(cs--) solve();
return 0;
}