「BZOJ2391」Cirno的忧郁

传送门

设p[0] = (-10001,-10001)

把所有点按p[0]极角排序,

s[i][j]表示三角形p[0]p[i]p[j]内的总价值,若i到j极角增大则s为正,否则s为负。

那么答案就是按顺序多边形每条边两个端点的s值之和的绝对值。

如何求s

枚举每个点x,建一颗平衡树,把极角排序在它后面的点一个个加入平衡树,树中的权值为按x极角排序的值。那么加入一个点y时,权值小于y的权值的所有点的和即为s[x][y]。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#define eps 1e-15
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=2007;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,q,qs[N],rak[N];

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct pt {
    LL x,y,w; int id; db slop;
    pt(){}
    pt(LL x,LL y):x(x),y(y){}
}p[N];
pt operator - (const pt&A,const pt&B) { return pt(A.x-B.x,A.y-B.y); }
LL cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
LL dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
LL length(pt A) { return dot(A,A); }
int dcmp(db x) { return fabs(x)<=eps?0:(x>0?1:-1); } 
bool operator <(const pt&A,const pt&B) { 
    return dcmp(A.slop-B.slop)>0||(dcmp(A.slop-B.slop)==0&&length(A-p[0])<length(B-p[0])); 
} 

db v[N];
LL w[N],s[N][N],sum[N],rs;
int rt,tot,l[N],r[N],hr[N];
#define lc l[x]
#define rc r[x]
void update(int x) { sum[x]=sum[lc]+sum[rc]+w[x]; }

void left(int &x) {
    int y=r[x];
    r[x]=l[y];
    l[y]=x;
    update(x);
    x=y;
    update(x);
}

void right(int &x) {
    int y=l[x];
    l[x]=r[y];
    r[y]=x;
    update(x);
    x=y;
    update(x);
} 

void insert(int &x,db y,LL ww) {
    if(!x) {
        x=++tot;
        hr[x]=rand();
        lc=rc=0;
        v[x]=y;
        sum[x]=w[x]=ww; 
        rs+=ww;
        return ;
    }
    if(v[x]<y) {
        rs+=sum[lc]+w[x];
        insert(rc,y,ww);
        if(hr[rc]<hr[x]) left(x);
    }
    else {
        insert(lc,y,ww);
        if(hr[lc]<hr[x]) right(x);
    }
    update(x);
}

LL solve(int k) {
    LL res=0;
    qs[k+1]=qs[1];
    For(i,1,k) 
        res+=s[rak[qs[i]]][rak[qs[i+1]]];
    return abs(res);
}

#define DEBUG
int main() {
#ifdef DEBUG
    freopen("2391.in","r",stdin);
    freopen("2391.out","w",stdout);
#endif
    srand(998244353);
    read(n); read(m);
    For(i,1,n) read(p[i].x),read(p[i].y),p[i].id=i,p[i].w=0;
    For(i,1,m) read(p[n+i].x),read(p[n+i].y),read(p[n+i].w);
    p[0]=pt(-12345,-15432); 
    For(i,1,n+m) p[i].slop=atan2(p[i].y-p[0].y,p[i].x-p[0].x);
    sort(p+1,p+n+m+1);
    For(i,1,n+m) if(p[i].id) rak[p[i].id]=i;
    For(i,1,n+m) {
        rt=0; tot=0;
        For(j,i,n+m) {
            if(j==1008) {
                int debug=1;
            }
            rs=0;
            insert(rt,atan2(p[j].y-p[i].y,p[j].x-p[i].x),p[j].w);
            s[i][j]=rs; s[j][i]=-rs;
        }
    }
    read(q);
    while(q--) {
        int k;
        read(k);
        For(i,1,k) read(qs[i]);
        printf("%lld\n",solve(k)); 
    }
    return 0;
}
View Code

 

posted @ 2018-03-28 11:21  啊宸  阅读(263)  评论(0编辑  收藏  举报