题意:
给n个点,m个物品,每个物品有一个权值,求从这n个点中选出若干点能圈住的物品权值和。
n≤2000,m≤2000
题解:
先预处理n个点两两点对与原点组成的三角形能圈住的物品总和
sum[i][j]
(顺时针为正,逆时针为负)。然后就可以用求多边形面积的经典方法求解,主要是怎么处理第一部分:
观察可得,按到原点的极角排序后,两点能圈住的距离是夹在两直线中间的直线,比如 C,D,G 三点,且 DC−→−×DG−→−≥0 。直接以每个点为起点扫一遍即可。查找满足的向量放在平衡树中查找。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const double eps=1e-10;
struct IO{
streambuf *ib,*ob;
inline void init(){
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
ib=cin.rdbuf();ob=cout.rdbuf();
}
inline int read(){
char ch=ib->sbumpc();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}
return i*f;
}
inline void W(ll x){
static int buf[50];
if(!x){ob->sputc('0');return;}
if(x<0){ob->sputc('-');x=-x;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
}
inline uint unit(){
static uint state0=19491001;
state0^=state0<<13;
state0^=state0>>17;
state0^=state0<<5;
return state0;
}
}io;
const int Maxn=2e3+50;
struct point{
int x,y,id,val;
double slope;
point(int x=0,int y=0):x(x),y(y){}
friend inline point operator -(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
friend inline int operator *(const point &a,const point &b){return a.x*b.y-a.y*b.x;}
inline int dis()const{return x*x+y*y;}
}p[Maxn<<2];
int n,m,sum[Maxn][Maxn],val[Maxn];
inline bool cmp(const point &a,const point &b){
if(a.slope!=b.slope)return a.slope<b.slope;
else if(a.x!=b.x)return a.dis()<b.dis();
else return a.id<b.id;
}
struct node{
node *lc,*rc;
int sum,val;
double slope;
uint pri;
inline void upt(){
sum=lc->sum+rc->sum+val;
}
}Pool[Maxn<<1],*pool=Pool,*null=Pool;
inline node* newnode(){
++pool;pool->lc=pool->rc=null;
return pool;
}
typedef pair<node*,node*> pii;
struct Treap{
node *rt;
inline void reset(){
rt=null;pool=Pool;
}
inline node* merge(node *x,node *y){
if(x==null)return y;if(y==null)return x;
if(x->pri>y->pri){
x->rc=merge(x->rc,y);x->upt();
return x;
}else{
y->lc=merge(x,y->lc);y->upt();
return y;
}
}
inline pii split(node *&now,double slope){
if(now==null)return make_pair(null,null);
if(now->slope<slope){
pii tr=split(now->rc,slope);
now->rc=tr.first;now->upt();
return make_pair(now,tr.second);
}else{
pii tr=split(now->lc,slope);
now->lc=tr.second;now->upt();
return make_pair(tr.first,now);
}
}
inline void insert(double slope,int val){
pii tr=split(rt,slope);
node *tmp=newnode();tmp->pri=io.unit();tmp->slope=slope;tmp->val=tmp->sum=val;
rt=merge(tr.first,merge(tmp,tr.second));
}
inline int ask(double slope){
double slope2=slope+PI+eps;
pii tr=split(rt,slope);
pii tr2=split(tr.second,slope2);
int tmp=tr2.first->sum;
rt=merge(tr.first,merge(tr2.first,tr2.second));
if(slope2>PI){
tr=split(rt,slope2-2*PI+eps);
tmp+=tr.first->sum;
rt=merge(tr.first,tr.second);
}
return tmp;
}
}treap;
int main(){
io.init();n=io.read();m=io.read();null->lc=null->rc=null;
int id;
for(int i=1;i<=n;i++){p[i].x=io.read(),p[i].y=io.read();p[i].id=i;p[i].val=0;p[i].slope=atan2(p[i].y,p[i].x);}
for(int i=1;i<=m;i++){p[n+i].x=io.read(),p[n+i].y=io.read();p[n+i].id=0;p[n+i].val=io.read();p[n+i].slope=atan2(p[n+i].y,p[n+i].x);}
sort(p+1,p+n+m+1,cmp);
memcpy(p+n+m+1,p+1,sizeof(point)*(n+m));
for(int i=1;i<=n+m;i++){
if(p[i].id==0)continue;
treap.reset();
for(int j=i+1;j<i+n+m;j++){
if(p[i]*p[j]<=0)break;
double slope=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
if(p[j].id){
sum[p[i].id][p[j].id]=treap.ask(slope);
sum[p[j].id][p[i].id]=-sum[p[i].id][p[j].id];
}
else{
treap.insert(slope,p[j].val);
}
}
}
int q=io.read();
for(int i=1;i<=q;i++){
int cnt=io.read();
long long ans=0;
static int a[Maxn];
for(int j=1;j<=cnt;j++)a[j]=io.read();
a[cnt+1]=a[1];
for(int j=1;j<=cnt;j++)ans+=sum[a[j]][a[j+1]];
io.W(abs(ans));io.ob->sputc('\n');
}
}