• [Codeforces]853E


    题目大意:给出平面上$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]);
    }
  • 相关阅读:
    欢迎参加MVP主讲的Windows 10开发线上课程
    SharePoint 2013 重复的管理账户错误:已添加项。字典中的关键字 所添加的关键字
    SharePoint 2013 开发——SharePoint Designer 2013工作流
    SharePoint 2013 开发——构建工作流开发环境
    SharePoint 2013 开发——工作流架构
    SharePoint 2013 开发——APP安全模型
    SharePoint 2013 开发——SharePoint APP介绍
    SharePoint 2013 开发——概述
    win32
    hdu2100 26进制加法
  • 原文地址:https://www.cnblogs.com/ditoly/p/CF853E.html
Copyright © 2020-2023  润新知