HAOI2011 防线修建

题目链接:戳我

动态维护凸包的题目qwqwq

30分还是很好写的。。直接一个凸包就完事了
代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,nx,ny,m,q,op,top;
int nvis[MAXN];
struct Node{int x,y,id;}node[MAXN],st[MAXN];

inline bool cmp(struct Node a,struct Node b)
{
    double A=atan2((a.y-node[1].y),(a.x-node[1].x));
    double B=atan2((b.y-node[1].y),(b.x-node[1].x));
    if(A!=B) return A<B;
    return a.x<b.x;
}

inline double cross(Node a,Node b,Node c)
{
    a.x-=c.x,a.y-=c.y;
    b.x-=c.x,b.y-=c.y;
    return a.x*b.y-a.y*b.x;
}

inline void solve()
{
    node[0]=(Node){0x3f3f3f3f,0x3f3f3f3f};
    int pos=0;
    for(int i=1;i<=m;i++)
        if(node[i].y<node[pos].y||(node[i].y==node[pos].y&&node[i].x<node[pos].x)&&!nvis[node[i].id])
            pos=i;
    int tmp=1;top=1;
    swap(node[1],node[pos]);
    sort(&node[2],&node[m+1],cmp);
    while(nvis[node[tmp].id]) tmp++; st[0]=node[tmp],tmp++;
    while(nvis[node[tmp].id]) tmp++; st[1]=node[tmp],tmp++;
    for(int i=tmp;i<=m;i++)
    {
        if(nvis[node[i].id]) continue;
        while(top&&cross(st[top-1],node[i],st[top])>0.0) top--;
        st[++top]=node[i];
    }
}

inline double dist(Node a,Node b)
{
    double cur_ans=sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
    return cur_ans;
}

inline double query()
{
    double ans=0;st[top+1]=st[0];
    for(int i=0;i<=top;i++) ans+=dist(st[i],st[i+1]);
    return ans;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&nx,&ny);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int cur_x,cur_y;
        scanf("%d%d",&cur_x,&cur_y);
        node[i]=(Node){cur_x,cur_y,i};
    }
    node[++m]=(Node){0,0,m};
    node[++m]=(Node){n,0,m};
    node[++m]=(Node){nx,ny,m};
    scanf("%d",&q);
    solve();
    while(q--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            int x;
            scanf("%d",&x);
            nvis[x]=1;
            solve();
        }
        else printf("%.2lf\n",query()-n);
    }
    return 0;
}

然后满分做法怎么做呢?其实是一个动态凸包的模板啦!!

动态凸包只资瓷加点,所以我们把所有的询问先离线下来,然后倒着做。

排序方法有两种,一种是水平的,一种是极角的。(水平序听说维护起来很麻烦的样子)这里采用的是极角序,当极角相同的时候,按照它和凸包的中心点的远近来排序。

因为题目中已经给出了三个点,所以这个中心点就是这个三角形的中心啦!

我们往里面加点的时候,设nxt为第一个极角比x大的,pre为第一个极角比x小的。这里的前驱后继寻找肯定不能O(n)了,我们采用logn的数据结构平衡树!!!set。

然后如果这个x点已经在凸包里面了,我们就可以return了,不需要任何其他操作了。

但是如果这个点在凸包的外面,显然要把pre和nxt之间的边断掉,加入pre到x和nxt到x的边。

然后还需要考虑两种情况,一种是极角比pre小的一些点是否在x加进来之后成为了凹进去的点(也就是夹角大于180度)?对应的另一种情况是极角nxt大的点。

所以我们还要用两个while来进行判断。

整体时间复杂度上限为\(O(nlogn)\)。

因为蒟蒻不会做动态凸包,所以思路上很大程度上参考自这位大佬,在此表示深深的感激qwqwq。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define eps 1e-6
#define MAXN 100010
using namespace std;
int n,x,y,m,q,tot;
bool del[MAXN];
double cur_ans;
double ans[MAXN];
struct Node{
    double x,y,ang,len;
    Node(double x=0,double y=0,double ang=0,double len=0):
        x(x),y(y),ang(ang),len(len){}
}a[MAXN],o;
struct Que{int id,op;}que[MAXN];
set<Node>st;
set<Node>::iterator nxt,pre,tmp;
inline bool operator < (const Node &a,const Node &b)
{
    if(fabs(a.ang-b.ang)<eps) return a.len<b.len;
    return a.ang<b.ang;
}
inline Node operator - (const Node a,const Node b){return (Node){a.x-b.x,a.y-b.y};}
inline double dot(Node a,Node b){return a.x*b.x+a.y*b.y;}
inline double cross(Node a,Node b){return a.x*b.y-a.y*b.x;}
inline double get_len(Node a){return sqrt(dot(a,a));}
inline set<Node>::iterator get_pre(set<Node>::iterator it)
{
    if(it==st.begin()) it=st.end();
    it--;
    return it;
}
inline set<Node>::iterator get_nxt(set<Node>::iterator it)
{
    it++;
    if(it==st.end()) it=st.begin();
    return it;
}
inline void solve(Node x)
{
    nxt=st.lower_bound(x);
    if(nxt==st.end()) nxt=st.begin();
    pre=get_pre(nxt);
    if(cross((*nxt)-(*pre),x-(*pre))>=0) return;
    cur_ans-=get_len((*nxt)-(*pre));
    cur_ans+=get_len(x-(*nxt))+get_len(x-(*pre));
    st.insert(x);
    tmp=get_pre(pre);
    while(cross(x-(*pre),(*pre)-(*tmp))>=0)
    {
        cur_ans-=get_len(x-(*pre))+get_len((*pre)-(*tmp));
        cur_ans+=get_len(x-(*tmp));
        st.erase(pre);
        pre=tmp;
        tmp=get_pre(pre);
    }
    tmp=get_nxt(nxt);
    while(cross(x-(*nxt),(*nxt)-(*tmp))<=0)
    {
        cur_ans-=get_len(x-(*nxt))+get_len((*nxt)-(*tmp));
        cur_ans+=get_len(x-(*tmp));
        st.erase(nxt);
        nxt=tmp;
        tmp=get_nxt(nxt);
    }
    return;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&x,&y);
    a[0]=(Node){0,0};
    a[1]=(Node){n,0},o.x+=n;
    a[2]=(Node){x,y},o.x+=x,o.y+=y;
    cur_ans+=get_len(a[2]-a[0])+get_len(a[2]-a[1]);
    o.x/=3,o.y/=3;
    for(int i=0;i<=2;i++)
    {
        a[i].ang=atan2(a[i].y-o.y,a[i].x-o.x);
        a[i].len=get_len(a[i]-o);
        st.insert(a[i]);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lf%lf",&a[i].x,&a[i].y);
        a[i].ang=atan2(a[i].y-o.y,a[i].x-o.x);
        a[i].len=get_len(a[i]-o);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&que[i].op);
        if(que[i].op==1) scanf("%d",&que[i].id),del[que[i].id]=true;
    }
    for(int i=1;i<=m;i++)
        if(del[i]==false)
            solve(a[i]);
    for(int i=q;i>=1;i--)
    {
        if(que[i].op==2) ans[++tot]=cur_ans;
        else solve(a[que[i].id]);
    }
    for(int i=tot;i;i--) printf("%.2lf\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/10459598.html

时间: 2024-10-10 23:45:24

HAOI2011 防线修建的相关文章

BZOJ 2300: [HAOI2011]防线修建( 动态凸包 )

离线然后倒着做就变成了支持加点的动态凸包...用平衡树维护上凸壳...时间复杂度O(NlogN) ----------------------------------------------------------------------- #include<cmath> #include<cstdio> #include<cctype> #include<cstring> #include<cstdlib> #include<algori

【BZOJ 2300】 2300: [HAOI2011]防线修建 (动态凸包+set)

2300: [HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 1.给出你所有的A国城市坐标 2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了 3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

【BZOJ2300】[HAOI2011]防线修建 set维护凸包

[BZOJ2300][HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 1.给出你所有的A国城市坐标 2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了 3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少

bzoj千题计划236:bzoj2300: [HAOI2011]防线修建

http://www.lydsy.com/JudgeOnline/problem.php?id=2300 维护动态凸包,人懒用的set 用叉积判断,不要用斜率 #include<set> #include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 100001 struct node { int x,y; node(int x_=0,int y_=0):

【题解】P2521 [HAOI2011]防线修建(动态凸包)

[题解]P2521 [HAOI2011]防线修建(动态凸包) 凸包是易插入不好删除的东西,按照剧情所以我们时光倒流 然后问题就是维护凸包的周长,支持加入 本来很简单,但是计算几何就是一些小地方经验不足容易WA和RE 然后代码注释里有一些经验 //@winlere #include<iostream> #include<set> #include<cstdio> #include<cstring> #include<algorithm> #incl

cogs 547:[HAOI2011] 防线修建

★★★☆   输入文件:defense.in   输出文件:defense.out   简单对比 时间限制:1 s   内存限制:128 MB 题目描述: 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 给出你所有的A国城市坐标 A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不

BZOJ [HAOI2011]防线修建(动态凸包)

听说有一种很高端的东西叫动态凸包维护dp就像学一下,不过介于本人还不会动态凸包就去学了下,还是挺神奇的说,维护上下凸包的写法虽然打得有点多不过也只是维护复制黏贴的事情而已罢了. 先说下动态凸包怎么写吧,搞棵平衡树存上下凸壳然后每次插入一个点就往他左右维护看是否满足凸性否则就弹出,就是这么简单 这道题就是删点然后询问凸壳,那么离线反着做就行了 出题人还是挺良心的直接让你维护上凸壳就行了,还不用管边界条件 用set打了一下,比较慢但还是挺好打的= = 换新blog挺多功能得试试的,现在想搞个像HZW

BZOJ-2300 [HAOI2011]防线修建

将问题离线倒序处理,问题变成动态加点维护凸包. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <cctype> #include <set> #define rep(i, l, r) for(int i=l; i&

[日常摸鱼]Luogu2521[HAOI2011]防线修建-set维护凸包

https://www.luogu.org/problemnew/show/2521 题意:维护一个上凸包:删点,查询周长 很容易想到把问题转换为离线:先读入全部操作,记录下最后剩下的点,倒着加点来维护凸包,同时也倒着做询问. 然后问题就变成了怎么维护加点的操作,这题其实只要维护上半个凸包(其实也有一点启发性了吧),用set存凸包的点集,对于要加的点往左右两边一直把不行的点删掉就好了,因为一个点最多被删一次所以加上set的$log$实际复杂度是$O(nlog n)$的而不是$O(n^2)$. 如

Luogu-2521 [HAOI2011]防线修建

倒过来处理所有询问,就变成了一道动态凸包的裸题 吐槽一下这道题只要维护上凸壳就好了,我zz了没好好看题打了两个2333 // luogu-judger-enable-o2 #include<set> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define rp (*r) #define lp (*l) #define rrp (*rr) #def