[bzoj4822][Cqoi2017]老C的任务&[bzoj1935][Shoi2007]Tree 园丁的烦恼

时间:2023-12-05 15:48:38
来自FallDream的博客,未经允许,请勿转载,谢谢。

老 C 是个程序员。    
最近老 C 从老板那里接到了一个任务——给城市中的手机基站写个管理系统。作为经验丰富的程序员,老 C 轻松地完成了系统的大部分功能,并把其中一个功能交给你来实现。由于一个基站的面积相对于整个城市面积来说非常的小,因此每个的基站都可以看作坐标系中的一个点,其位置可以用坐标(x, y)来表示。此外,每个基站还有很多属性,例如高度、功率等。运营商经常会划定一个区域,并查询区域中所有基站的信息。现在你需要实现的功能就是,对于一个给定的矩形区域,回答该区域中(包括区域边界上的)所有基站的功率总和。如果区域中没有任何基站,则回答 0。
n,m不知道多大 反正不会太大 不会超过500000吧  然后权值和坐标应该是int
因为没有强制在线,所以考虑离线,按照x坐标排序,y坐标离散之后插入线段树。
询问可以拆成两个,差分一下即可。
复杂度nlogn
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define MN 1000000
#define N 524288
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
}
ll Ans[MN+],t[N*+];
int cm=,n,m,cnt=,Y[MN+];
struct Tree{int x,y,z;}T[MN+];
struct ques{int x,l,r,id,ad;}q[MN*+];
bool cmp(ques x,ques y){return x.x<y.x;}
bool cmp2(Tree x,Tree y){return x.x<y.x;}
inline void Renew(int x,int ad){for(t[x+=N]+=ad,x>>=;x;x>>=)t[x]=t[x<<]+t[x<<|];}
inline ll Query(int l,int r)
{
if(l>r) return ;ll sum=;
for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
{
if(~l&) sum+=t[l+];
if( r&) sum+=t[r-];
}
return sum;
}
int main()
{
n=read();m=read();
for(int i=;i<=n;++i) T[i].x=read(),Y[i]=T[i].y=read(),T[i].z=read();
sort(Y+,Y+n+);
for(int i=;i<=n;++i) if(Y[i]!=Y[i-]) Y[++cm]=Y[i];
for(int i=;i<=n;++i)
T[i].y=lower_bound(Y+,Y+cm+,T[i].y)-Y;
for(int i=;i<=m;++i)
{
int X1=read(),Y1=read(),X2=read(),Y2=read();
Y1=lower_bound(Y+,Y+cm+,Y1)-Y;
Y2=upper_bound(Y+,Y+cm+,Y2)-Y-;
q[++cnt]=(ques){X1-,Y1,Y2,i,-};
q[++cnt]=(ques){X2,Y1,Y2,i,};
}
sort(q+,q+cnt+,cmp);
sort(T+,T+n+,cmp2);
for(int i=,j=;j<=cnt;)
if(i<=n&&T[i].x<=q[j].x) Renew(T[i].y,T[i].z),++i;
else Ans[q[j].id]+=q[j].ad*Query(q[j].l,q[j].r),++j;
for(int i=;i<=m;++i) printf("%lld\n",Ans[i]);
return ;
}