题目大意
二维平面上一开始有n个点,每个点有一个初始亮度s,每过一个时间单位,每个点的亮度会增加1,如果当前亮度为c,那么再增加一次之后亮度会变为0.
q个询问,每次询问给一个时刻t和一个矩阵,问该时刻的时候这个矩阵内点的总亮度是多少。
(n,q,x,y <= 5e4, c<=1e9,0<=s,t<=c)
题解:
把一个询问拆分成四个前缀和询问,则每次询问在(x,y)内的点,在t时刻的总亮度。因为超过c之后会重新计数,又因为(t<=c),所以在当前查询的时候,一个星星的亮度最多有一次超过c。超过部分的贡献是 (超出c的星星数量)*(c+1),所以要减去这个值。
所以查询变成,询问(0,0,x,y)内,初始亮度为[0,c-t]的星星数量和总的星星数量。转换成三维偏序问题,CDQ分治求一下就可以啦。
因为c太大所以要离散化。
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const int maxn = 5e4 + 50;
ll sz[maxn], val[maxn];
void add(ll *a, int i, ll x){while(i < maxn) a[i] += x, i += lowbit(i);return;}
ll qry(ll *a, int i){ll res = 0;while(i) res += a[i], i -= lowbit(i); return res;}//树状数组操作
int n, q;
ll c, ans[maxn];
struct node{
int x, y, op, id;//op代表操作类型,id代表一个询问的初始位置
ll t, pos;//pos为离散化后的查询点/修改点
bool operator < (const node& a)const {
if(x!=a.x) return x < a.x;
return op < a.op;//如果x坐标相同,插入要优先于查询
}
}e[maxn*10], temp[maxn*10];
ll cc[maxn*4];//离散化数组
int num;//离散化用
void cdq(int l, int r)
{
if(r-l <= 1) return;
int mid = (r+l)>>1;
cdq(l, mid); cdq(mid, r);
int lp = l, rp = mid, o = 0;
while(lp < mid && rp < r){
if(e[lp].y <= e[rp].y){
if(e[lp].op == -2){//加入星星
add(sz, e[lp].pos, 1);
add(val, e[lp].pos, e[lp].t);
}
temp[o++] = e[lp++];
}
else{
if(e[rp].op != -2){
ll v = qry(val, num);//总的初始价值
ll cnt1 = qry(sz, num);//总的星星
ll cnt2 = qry(sz, e[rp].pos);//在[0, c-t]的星星
ans[e[rp].id] += e[rp].op*( v + cnt1*(e[rp].t) - (cnt1 - cnt2)*(c+1) );
}
temp[o++] = e[rp++];
}
}
while(rp < r){//先把查询处理完
if(e[rp].op != -2){
ll v = qry(val, num);
ll cnt1 = qry(sz, num), cnt2 = qry(sz, e[rp].pos);
ans[e[rp].id] += e[rp].op*( v + cnt1*(e[rp].t) - (cnt1 - cnt2)*(c+1) );
}
temp[o++] = e[rp++];
}
for(int i = l; i < lp; ++i){//删除之前的更改
if(e[i].op == -2){
add(sz, e[i].pos, -1);
add(val, e[i].pos, -e[i].t);
}
}
while(lp < mid) temp[o++] = e[lp++];//再把左边剩余的处理完
for(int i = 0; i < o; ++i) e[i+l] = temp[i];
return;
}
int main()
{
scanf("%d%d%lld", &n, &q, &c);
num = 0;
for(int i = 0; i < n; ++i){
scanf("%d%d%lld", &e[i].x, &e[i].y, &e[i].t);
e[i].op = -2; e[i].pos = e[i].t;
cc[++num] = e[i].t;
}
int idq = n;
for(int i = 0; i < q; ++i){
int x1, x2, y1, y2; ll t;
scanf("%lld%d%d%d%d", &t, &x1, &y1, &x2, &y2);
e[idq].op = 1, e[idq].x = x1 - 1, e[idq].y = y1 - 1, e[idq].id = i, e[idq].t = t, e[idq++].pos = c-t;
e[idq].op = 1, e[idq].x = x2, e[idq].y = y2, e[idq].id = i, e[idq].t = t, e[idq++].pos = c-t;
e[idq].op = -1, e[idq].x = x2, e[idq].y = y1 - 1, e[idq].id = i, e[idq].t = t, e[idq++].pos = c-t;
e[idq].op = -1, e[idq].x = x1 - 1, e[idq].y = y2, e[idq].id = i, e[idq].t = t, e[idq++].pos = c-t;
cc[++num] = c - t;
}
sort(e, e+idq);
sort(cc+1, cc+num+1); num = unique(cc+1,cc+1+num) - cc - 1;//按照x坐标从小到大排序
for(int i = 0; i < idq; ++i) e[i].pos = lower_bound(cc+1,cc+1+num, e[i].pos) - cc;
cdq(0, idq);
for(int i = 0; i < q; ++i) printf("%lld\n", ans[i]);
}