AmazingCounters.com

[Codeforces]853E - Lada Malina

题目大意:给出平面上$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-t\sum v_{j}+\sum w_{j}v_{j}(0<=w_{j}<=2t)$,令$P=p-t\sum 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\n",ans[i]);
}

 

posted on 2017-09-07 14:38  ditoly  阅读(343)  评论(0编辑  收藏  举报