您的位置:首页 > 其它

【NOI2015模拟1.17】⑨

2018-01-04 17:38 344 查看

Description

Cirno闲着无事的时候喜欢冰冻青蛙。

Cirno每次从雾之湖中固定的n个结点中选出一些点构成一个简单多边形,Cirno运用自己的能力能将此多边形内所有青蛙冰冻。

雾之湖生活着m只青蛙,青蛙有大有小,所以每只青蛙的价值为一个不大于10000的正整数。

Cirno很想知道每次冻住的青蛙的价值总和。因为智商有限,Cirno将这个问题交给完美算术教室里的你。

因为爱护动物,所以每次冻结的青蛙会被放生。也就是说一只青蛙可以被多次统计。

-10000<=x,y<=10000; 0

Solution

计算几何式懵逼

我们知道可以先选择一个原点,然后通过类似叉积的做法求出这个多边形的有向面积

这里的面积定义成内部的点的个数

于是我们只需要求出每个三角形内部的点的权值和,两次排序之后树状数组维护即可。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef double db;
typedef long long ll;

const int N=1e3+5;

int n,m,ans,Q,a
,ord
,S,Ans[N<<1][N<<1],tr[N<<1];
db eps=1e-7;

void ins(int x,int y) {for(;x<=n+m;x+=x&-x) tr[x]+=y;}
int query(int x) {int res=0;for(;x;x-=x&-x) res+=tr[x];return res;}
int find(int l,int r) {
if (l>r) swap(l,r);
return query(r)-query(l-1);
}

struct P{
int x,y,v,id,w;db a;
P(int _x=0,int _y=0) {x=_x;y=_y;v=id=w=a=0;}
friend P operator + (P x,P y) {return P(x.x+y.x,x.y+y.y);}
friend P operator - (P x,P y) {return P(x.x-y.x,x.y-y.y);}
}p[N<<1],O,q[N<<1];

int cross(P x,P y) {return x.x*y.y-y.x*x.y;}

int sig(int x) {
if (x>0) return 1;
if (x==0) return 0;
if (x<0) return -1;
}

bool cmp(P x,P y) {return x.a<y.a;}

db theta(P x,P y) {
db a=x.x*y.x+x.y*y.y;
a/=sqrt(x.x*x.x+x.y*x.y)*sqrt(y.x*y.x+y.y*y.y);
return acos(a);
}

int main() {
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d%d",&p[i].x,&p[i].y),p[i].id=i;
fo(i,1,m) scanf("%d%d%d",&p[i+n].x,&p[i+n].y,&p[i+n].v);
O=P(-20000,-20000);
fo(i,1,n+m) p[i].a=atan2(p[i].y-O.y,p[i].x-O.x);
sort(p+1,p+n+m+1,cmp);
fo(i,1,n+m) {
p[i].w=i;
if (p[i].id) ord[p[i].id]=i;
}
fo(i,1,n+m)
if (!p[i].v) {
int tot=0;
fo(j,i+1,n+m) {
q[++tot]=p[j];
q[tot].a=theta(p[j]-O,p[i]-O)+theta(O-p[j],p[i]-p[j]);
}
sort(q+1,q+tot+1,cmp);
fo(j,1,tot)
if (q[j].v) ins(q[j].w,q[j].v);
else Ans[i][q[j].w]=Ans[q[j].w][i]=find(q[j].w,p[i].w);
fo(j,1,tot) if (q[j].v) ins(q[j].w,-q[j].v);
}
for(scanf("%d",&Q);Q;Q--) {
scanf("%d",&S);
int ans=0;
fo(i,1,S) {
scanf("%d",&a[i]);a[i]=ord[a[i]];
if (i!=1) ans+=sig(cross(p[a[i]]-O,p[a[i-1]]-O))*Ans[a[i]][a[i-1]];
}
ans+=sig(cross(p[a[1]]-O,p[a[S]]-O))*Ans[a[1]][a[S]];
if (ans<0) ans=-ans;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: