【省选组】模拟 gmoj.3976. 【NOI2015模拟1.17】⑨

Cirno闲着无事的时候喜欢冰冻青蛙。
Cirno每次从雾之湖中固定的n个结点中选出一些点构成一个简单多边形,Cirno运用自己的能力能将此多边形内所有青蛙冰冻。
雾之湖生活着m只青蛙,青蛙有大有小,所以每只青蛙的价值为一个不大于10000的正整数。
Cirno很想知道每次冻住的青蛙的价值总和。因为智商有限,Cirno将这个问题交给完美算术教室里的你。
因为爱护动物,所以每次冻结的青蛙会被放生。也就是说一只青蛙可以被多次统计。

这道题是一道计算几何的基础题,适合最近在练习计算几何的我。

遇到这种类型的问题,其实很容易解决,我们给每条边定一个方向,设其为从横坐标较小的点到较大的点。

对于正方向的边,这条边下方的所有的权值按正的算,负方向的点,这条边下方的所有的权值按负的算。

对于一个点,我们可以将所有点分成在左侧和在右侧两部分,按斜率排序,从低到高,依次加入线段树统计答案。

这题一开始被卡了时间,要注意斜率要提前处理,可以快很多。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 3000
#define db double
#define mxp 10000
#pragma GCC optimize(3)
using namespace std;
int n,m,q,s,g[N],i,j,ans,sum,temp,f[mxp*10],tp[N][N],x,y,bz[N];
db kp;
struct node{
    int x,y,val,id;
    db kp;
}p1[N],p2[N];
db xp1=atan2(0,-1),xp2=atan2(-1,0),xp3=atan2(1,0);
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-')
            f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline db Abs(db x){
    if (x<0) return -x;
    return x;
}
inline int cmp(node a,node b){
    if (a.kp!=b.kp)
        return a.kp<b.kp;
    return a.x<b.x;
}
inline void insert(int x,int l,int r,int k,int p){
    if (l==r){
        f[x]+=p;
        return;
    }
    int mid=(l+r)/2;
    if (k<=mid)
        insert(x*2,l,mid,k,p);
    else
        insert(x*2+1,mid+1,r,k,p);
    f[x]=f[x*2]+f[x*2+1];
}
inline int getsum(int x,int l,int r,int l1,int r1){
    if (l1>r1)
        return 0;
    if (l1<=l&&r1>=r)
        return f[x];
    int mid=(l+r)/2,sum=0;
    if (l1<=mid)
        sum+=getsum(x*2,l,mid,l1,r1);
    if (r1>mid)
        sum+=getsum(x*2+1,mid+1,r,l1,r1);
    return sum;
}
int main(){
    n=read();m=read();
    for (i=1;i<=n;i++)
        p1[i].x=read(),p1[i].y=read(),p1[i].id=i,p1[i].x+=mxp;
    for (i=1;i<=m;i++)
        p1[i+n].x=read(),p1[i+n].y=read(),p1[i+n].val=read(),p1[i+n].id=i,p1[i+n].x+=mxp;
    for (i=1;i<=n+m;i++) p2[i]=p1[i];
    for (i=1;i<=n;i++){
        x=p1[i].x,y=p1[i].y;
        for (j=1;j<=n+m;j++){
            p2[j].kp=atan2(p2[j].y-y,p2[j].x-x);
            kp=p2[j].kp;
            p2[j].kp=Abs(p2[j].kp-xp2);
            if (kp<xp1&&kp>xp3) p2[j].kp=2*Abs(xp1-xp2)-p2[j].kp;
        }
        sort(p2+1,p2+n+m+1,cmp);
        for (j=1;j<=n+m;j++)
            if (p2[j].id!=i||p2[j].val>0){
                if (p2[j].val){
                    if (p1[i].x<=p2[j].x)
                        insert(1,0,mxp*2,p2[j].x,p2[j].val);
                    else
                        insert(1,0,mxp*2,p2[j].x,-p2[j].val);
                }
                else{
                    if (p1[i].x<=p2[j].x)
                        tp[i][p2[j].id]=getsum(1,0,mxp*2,p1[i].x,p2[j].x-1);
                    else
                        tp[i][p2[j].id]=getsum(1,0,mxp*2,p2[j].x,p1[i].x-1);
                }
            }
        for (j=1;j<=n+m;j++)
            if (p2[j].val>0){
                if (p1[i].x<=p2[j].x)
                    insert(1,0,mxp*2,p2[j].x,-p2[j].val);
                else
                    insert(1,0,mxp*2,p2[j].x,p2[j].val);
            }
    }
    q=read();
    while (q--){
        s=read();
        for (i=1;i<=s;i++)
            g[i]=read();
        g[++s]=g[1];
        ans=0;
        for (i=1;i<s;i++)
            ans+=tp[g[i]][g[i+1]];
        if (ans<0) ans=-ans;
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13747194.html