[GXOI / GZOI2019]曲芸

トピックリンク[ https://www.luogu.org/problem/P5302 ]

考える:この質問は二つの質問の合併ということができます。注目\(C \)画分および\(A \)\(B \) 2つの部分に分割される画分の独立を算出することができます。まず、(C \)\スコア、ポイントを見つけるには、正方形にするかどうかを決定することです。したがって、回転軸が45°(座標であってもよい\((X、Y)\ ) 座標にマッピングされている\((X + Y、X-Y )\) 次に、古典的に変換することができる、 -理解することができる手で再生されません)走査線の問題。次いで、極値およびBスコアの寄与「が交換のために」回数に応じて求めることができます。Cashen;「とラインへのルートバックを行い、縦軸に相対的な順序を維持する」為替に「簡単に見つけることが、」:「交流について」明らかタイトルは、言ったので、その都度実施していることができます縦軸上での相対的な順序を変更する」を超えます。交換のための「ミート質問の意味。そして、何時間」、「それの最小数?我々は(サンプル1でその標的先もエッジにそれぞれ由来の元の開始点に対応することができる(1--2,2--4,3--3,4--1を\)\で、)環形成してもよい(試料1を\(1--2--4 \)\(3 \)自己ループ)は、各リングの比較的独立しています。置換に相当する実際の各環について、国内のリングのための交換の数:\(胴回り-1 \) および最小。従って最小その回数と:\(NUMBER N- \) これまでのところ、分析が終わりました。

実現:その上フェンウィックツリー上の離散した後、走査線を問題については。リングの数を求めるために、でもエッジなしで、直接決意の互いに素セットであなたは、セット数を持つことができます。需要および交点座標の数として、私が個人的に開始および終了ポイントがヒット座標(セット\)\内部、その後同様の方法で実装を逆に求める使用します。

コード:

#include<bits/stdc++.h>
#define in read()
using namespace std;
const int N=1e5+5;
const double eps=1e-7;
int n,a,b,c,k,xst,xed,ans1,ans2,cnt,num,cp,tt,anss;
int st[N],ed[N],fa[N];
struct nd{int id,h;}tp[N];
struct pot{double x,y;int x1;}tmp[N*5];
struct seg{double he;int v,l,r;}ct[N<<1];
struct cop{double xx;int e,re;}hh[N*10];
bool operator<(nd x,nd y){return x.h<y.h;}
bool operator<(pot x,pot y){return x.y>y.y;}
bool operator<(seg x,seg y){return x.he>y.he;}
inline bool cmp(cop x,cop y){return x.xx<y.xx;}
inline bool cmp1(cop x,cop y){return x.e<y.e;}
inline int read()
{
    int s=0,w=1; char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    return s*w;
}
int fd(int x){return fa[x]==x?x:fa[x]=fd(fa[x]);}
inline pot zg(pot w){return pot{w.x+w.y,w.x-w.y,0};}
set<nd>tqx;
inline pot pt(pot a1,pot b1,pot a2,pot b2)
{
    double k1=(1.0*(a1.y-b1.y))/(1.0*(a1.x-b1.x)),b11=a1.y-k1*a1.x;
    double k2=(1.0*(a2.y-b2.y))/(1.0*(a2.x-b2.x)),b22=a2.y-k2*a2.x;
    if(k1-k2==0) return pot{0,0,0};
    double x=(b22-b11)/(k1-k2),y=x*k1+b11;
    return pot{x,y,0};
}
inline void pre1()
{
    for(int i=1;i<=n;++i)
    {
        int fx=fd(i),fy=fd(tp[i].id);
        if(fx!=fy) fa[fx]=fy;
    }
    ans1=n;
    for(int i=1;i<=n;++i)
        if(fd(i)==i) --ans1;
}
inline void pre2()
{
    for(int i=1;i<=n;++i)
    {
        set<nd>::iterator it=tqx.upper_bound((nd){i,ed[i]});
        for(;it!=tqx.end();it++)
            tmp[++ans2]=pt(pot{1.0*xst,st[i],0},pot{1.0*xed,ed[i],0},pot{1.0*xst,st[it->id],0},pot{1.0*xed,ed[it->id],0});
        tqx.insert((nd){i,ed[i]});
    }
    cnt=ans2;
}
struct Tree{
    int c[N*10];
    inline int lowbit(int x){return x&(-x);}
    inline void upd(int x,int v)
    {
        while(x<=tt)c[x]+=v,x+=lowbit(x);
    }
    inline int query(int x)
    {
        int ans=0;
        while(x>0)ans+=c[x],x-=lowbit(x);
        return ans;
    }
}T;
inline void work()
{
    sort(tmp+1,tmp+cnt+1);
    sort(ct+1,ct+num+1);
    int ret=1;
    while(tmp[ret].y>ct[1].he&&ret<=cnt) ++ret;
    for(int i=1;i<=num;++i)
    {
        while(tmp[ret].y>ct[i].he&&ret<=cnt)
            anss+=(T.query(tmp[ret++].x1)>0);
        T.upd(ct[i].l,ct[i].v);
        T.upd(ct[i].r+1,-ct[i].v);
    }
    ans1+=anss*c,ans2+=anss*c;
    if(ans1>ans2) swap(ans1,ans2);
    printf("%d %d\n",ans1,ans2);
}
int main()
{
    n=in,a=in,b=in,c=in,xst=in,xed=in;
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=n;++i) st[i]=in;
    for(int i=1;i<=n;++i) ed[i]=in;
    for(int i=1;i<=n;++i) tp[i].h=ed[i],tp[i].id=i;
    sort(tp+1,tp+n+1);
    pre1();pre2();
    ans1=ans1*a+(ans2-ans1)*b;ans2*=a;
    k=in;
    for(int i=1;i<=k;++i)
    {
        double _x=1.0*read(),_y=1.0*read(),_r=1.0*read();
        pot pt11=zg(pot{_x,_y-_r,0}),pt12=zg(pot{_x+_r,_y,0});
        pot pt21=zg(pot{_x-_r,_y,0}),pt22=zg(pot{_x,_y+_r,0});
        ct[++num].he=pt11.y,ct[num].v=1;
        ct[++num].he=pt21.y,ct[num].v=-1;
        hh[++cp].xx=pt11.x,hh[cp].e=cp;
        hh[++cp].xx=pt12.x,hh[cp].e=cp;
        hh[++cp].xx=pt21.x,hh[cp].e=cp;
        hh[++cp].xx=pt22.x,hh[cp].e=cp;
    }
    for(int i=1;i<=cnt;++i) tmp[i]=zg(tmp[i]);
    for(int i=1;i<=cnt;++i)
        hh[++cp].xx=tmp[i].x,hh[cp].e=cp;
    sort(hh+1,hh+cp+1,cmp);
    for(int i=1;i<=cp;++i)
        hh[i].re=(i==1||(hh[i].xx-hh[i-1].xx>=eps))?++tt:tt;
    sort(hh+1,hh+cp+1,cmp1);
    int num2=num<<1;
    for(int i=1;i<=num2;++i,++i)
    {
        int pos=i+1>>1;
        ct[pos].l=hh[i].re;
        ct[pos].r=hh[i+1].re;
    }
    for(int i=num2+1;i<=cp;++i)
        tmp[i-num2].x1=hh[i].re;
    work();
    return 0;
}

おすすめ

転載: www.cnblogs.com/zmyzmy/p/11862909.html