题目大意:给出平面上$n$个带权点$f_{i}$,再给出$k$个向量$v_{i}$,每次询问给出一个点$p$和一个值$t$,求能满足$f_{i}+sum w_{j}v_{j}=p(-t<=w_{j}<=t)$的$f_{i}$的点权和。($n,q<=10^5,k<=10$)
做法:由于$v_{i}$与$-v_{i}$等价,我们先把每个向量的横坐标变成非负(在此基础上尽量使纵坐标也非负),再把询问的式子化成$p-tsum v_{j}+sum w_{j}v_{j}(0<=w_{j}<=2t)$,令$P=p-tsum v_{j}$,则合法的$f_{i}$会在这样一个凸多边形内:从$P$点开始,按斜率从小到大的顺序依次把向量接起来得到一个下凸壳,再从$P$点开始,按斜率从大到小顺序再接出一个上凸壳。现在我们要计算这个凸多边形内的点权和,我们只要知道每条边下方(以两个端点向下竖直画射线与这条边围成的区域)的点权和,上凸壳减下凸壳就是答案。由于斜率只有$k$种,我们每种斜率都做一遍,算出所有同斜率的边以及所有点在这个斜率下的截距,按这个截距的大小顺序,按横坐标建线段树即可统计。时间复杂度$O(k(n+q)logn)$。
一些实现细节可以参见如下代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ll long long inline int read() { int x,f=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')f=0; for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return f?x:-x; } #define MK 10 #define MN 100000 #define ps(x) (upper_bound(c+1,c+cn+1,x)-c-1) struct vec{int x,y;}v[MK+5]; struct work{double a;int x,y,z;}w[MN*2+5]; bool cmpv(const vec&a,const vec&b){return atan2(a.y,a.x)<atan2(b.y,b.x);} bool cmpw(const work&a,const work&b){return fabs(a.a-b.a)<1e-7?a.z<b.z:a.a<b.a;} int x[MN+5],y[MN+5],a[MN+5],c[MN+5],cn,sx,sy,px[MN+5],py[MN+5],t[MN+5]; ll ans[MN+5],s[MN+5]; void add(int k,int x){for(;k<=MN;k+=k&-k)s[k]+=x;} ll sum(int k){ll res=0;for(;k;k-=k&-k)res+=s[k];return res;} int main() { int k,n,q,i,j; k=read();n=read();q=read(); for(i=1;i<=k;++i) { v[i].x=read();v[i].y=read(); if(v[i].x<0)v[i].x=-v[i].x,v[i].y=-v[i].y; if(!v[i].x&&v[i].y<0)v[i].y=-v[i].y; sx+=v[i].x;sy+=v[i].y; } sort(v+1,v+k+1,cmpv); for(i=1;i<=n;++i)c[i]=x[i]=read(),y[i]=read(),a[i]=read(); sort(c+1,c+n+1);cn=unique(c+1,c+n+1)-c-1; for(i=1;i<=q;++i)px[i]=read(),py[i]=read(),t[i]=read(),px[i]-=sx*t[i],py[i]-=sy*t[i],t[i]<<=1; for(i=1;i<=k;++i) { if(!v[i].x){for(j=1;j<=q;++j)py[j]+=v[i].y*t[j];continue;} for(j=1;j<=n;++j)w[j]=(work){y[j]-(double)x[j]*v[i].y/v[i].x,x[j],a[j],0}; for(j=1;j<=q;++j)w[n+j]=(work){py[j]-(double)px[j]*v[i].y/v[i].x,px[j],px[j]+v[i].x*t[j],-j}, px[j]+=v[i].x*t[j],py[j]+=v[i].y*t[j]; sort(w+1,w+n+q+1,cmpw); memset(s,0,sizeof(s)); for(j=1;j<=n+q;++j) if(w[j].z)ans[-w[j].z]-=sum(ps(w[j].y))-sum(ps(w[j].x-(i<2))); else add(ps(w[j].x),w[j].y); } for(i=1;i<=k;++i) { if(!v[i].x)break; for(j=1;j<=n;++j)w[j]=(work){y[j]-(double)x[j]*v[i].y/v[i].x,x[j],a[j],0}; for(j=1;j<=q;++j)w[n+j]=(work){py[j]-(double)px[j]*v[i].y/v[i].x,px[j]-v[i].x*t[j],px[j],j}, px[j]-=v[i].x*t[j],py[j]-=v[i].y*t[j]; sort(w+1,w+n+q+1,cmpw); memset(s,0,sizeof(s)); for(j=1;j<=n+q;++j) if(w[j].z)ans[w[j].z]+=sum(ps(w[j].y-(i>1)))-sum(ps(w[j].x-1)); else add(ps(w[j].x),w[j].y); } for(i=1;i<=q;++i)printf("%I64d ",ans[i]); }