[bzoj2300][HAOI2011]防線修建(splay)

【題目鏈接】http://www.lydsy.com/JudgeOnline/problem.php?id=2300
【解題思路】離線倒序處理。問題就變成了每次加一個點維護凸包。用splay查找當前所加點對凸殼有影響的區間的兩個端點。splay以橫座標爲序,記錄每個點與前後兩個點的斜率。
【呆馬】

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
const int N=1e5+10;
const double inf=1e18,eps=1e-6;
using namespace std;
struct st{int l,r;double x,y,lk,rk;} New,a[N];
struct st1{int tag,x;} q[N<<1];
struct st2{double x,y;} p[N];
int n,m,l,r,t,i,last,root,ansn,fa[N];
double x,y,z,ans,Ans[N<<1];
bool del[N];
double dis(st a,st b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
double slo(st a,st b)
{
    if (fabs(a.x-b.x)<eps) return b.y>a.y?inf:-inf;
    return (b.y-a.y)/(b.x-a.x);
}
void zag(int x)
{
    int y=fa[x];
    if (a[fa[y]].l==y) a[fa[y]].l=x;
    else a[fa[y]].r=x;
    fa[x]=fa[y];
    if (!fa[x]) root=x;
    fa[y]=x;
    fa[a[x].l]=y;
    a[y].r=a[x].l;
    a[x].l=y;
}

void zig(int x)
{
    int y=fa[x];
    if (a[fa[y]].l==y) a[fa[y]].l=x;
    else a[fa[y]].r=x;
    fa[x]=fa[y];
    if (!fa[x]) root=x;
    fa[y]=x;
    fa[a[x].r]=y;
    a[y].l=a[x].r;
    a[x].r=y;
}

void splay(int x,int tag)
{
    for (;(!tag && fa[x]) || (tag && fa[x]!=root && fa[fa[x]]!=root);)
    {
        int y=fa[x],z=fa[y];
        if (!z)
        {
            if (a[y].l==x) zig(x);
            else zag(x);
        }
        else
        {
            if (a[y].l==x)
            {
                if (a[z].l==y) zig(y),zig(x);
                else zig(x),zag(x);
            }
            else
            {
                if (a[z].r==y) zag(y),zag(x);
                else zag(x),zig(x);
            }
        }
    }
    if (tag && fa[x]!=root)
    {
        if (a[fa[x]].l==x) zig(x);
        else zag(x);
    }
}

void findl(int p)
{
    if (!p || l==-1) return;
    if (abs(a[p].x-New.x)<eps && a[p].y>New.y){l=-1; return;}
    if (a[p].x>=New.x) findl(a[p].l);
    else if (slo(a[p],New)<a[p].lk) l=p,findl(a[p].r);
    else findl(a[p].l);
}

void findr(int p)
{
    if (!p || r==-1) return;
    if (abs(a[p].x-New.x)<eps && a[p].y>New.y){r=-1; return;}
    if (a[p].x<=New.x) findr(a[p].r);
    else if (slo(New,a[p])>a[p].rk) r=p,findr(a[p].l);
    else findr(a[p].r);
}

void dfs(int x)
{
    if (a[x].l) dfs(a[x].l);
    ans-=dis(a[x],a[last]);
    last=x;
    if (a[x].r) dfs(a[x].r);
}

void dele(int x)
{
    if (!x) return;
    fa[x]=a[fa[x]].l=0;
    dfs(x);
}

void insert(double x,double y)
{
    New.x=x;
    New.y=y;
    l=r=0;
    findl(root);
    findr(root);
    if (l<0 || r<0) return;
    splay(l,0);
    splay(r,1);
    a[++t].x=x;
    a[t].y=y;
    a[t].lk=slo(a[root],a[t]);
    a[t].rk=slo(a[t],a[a[root].r]);
    if (a[t].lk<a[t].rk){t--; return;}
    a[root].rk=a[t].lk;
    a[a[root].r].lk=a[t].rk;
    ans+=dis(a[l],New)+dis(a[r],New);
    last=l;
    dele(a[a[root].r].l);
    ans-=dis(a[last],a[r]);
    a[fa[t]=a[root].r].l=t;
}

int main()
{
        scanf("%lf%lf%lf\n%d\n",&z,&x,&y,&n);
        for (i=1;i<=n;i++) scanf("%lf%lf\n",&p[i].x,&p[i].y);
        scanf("%d\n",&m);
        for (i=1;i<=m;i++)
        {
            scanf("%d",&q[i].tag);
            if (q[i].tag==1)
            {
                scanf("%d",&q[i].x);
                del[q[i].x]=1;
            }
        }
        fa[a[1].l=2]=fa[t=a[1].r=3]=root=1;
        a[1].x=x;
        a[1].y=y;
        a[3].x=z;
        a[2].lk=inf;
        a[3].rk=-inf;
        a[1].lk=a[2].rk=slo(a[2],a[1]);
        a[1].rk=a[3].lk=slo(a[1],a[3]);
        ans=dis(a[1],a[2])+dis(a[1],a[3]);
        for (i=1;i<=n;i++)
            if (!del[i]) insert(p[i].x,p[i].y);
        for (;m;m--)
            if (q[m].tag==1) insert(p[q[m].x].x,p[q[m].x].y);
            else Ans[++ansn]=ans;
        for (;ansn;ansn--) printf("%.2f\n",Ans[ansn]);
}
發佈了33 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章