• LOJ576 「LibreOJ NOI Round #2」签到游戏


    题目
    先进行一个转化:
    每次花费(gcdlimits_{i=l+1}^rB_i)的代价,可以连((l,r))这一条边。
    然后我们需要求(0sim n)的最小生成树。
    根据Kruskal的思想,((0,n))这条边一定会被选。
    然后根据Prim的思想,对于某个点,我们需要找到其最短的出边。
    而显然对于(i),它最短的出边为((i,0))或者((i,n))。边权为(L_i=gcdlimits_{j=1}^iB_j)(R_i=gcdlimits_{j=i+1}^nB_j)
    显然(L_i)是单调不增,(R_i)是单调不减的。
    所以(exists pin[0,n),forall iin[0,p],R_ile L_i,forall iin(p,n),L_ile R_i)
    我们可以用线段树维护每个区间([l,r])(gcdlimits_{i=l+1}^rB_i),然后在线段树上二分求出(p)
    而题目所给的修改可以直接单点修改。
    剩下的就是求(sumlimits_{i=0}^pR_i+sumlimits_{i=p+1}^{n-1}L_i)
    考虑到(L_i)以及(R_i)的取值个数是(log n)级别的,我们可以在线段树上暴力找出这些取值以及其对应的区间。

    #include<cstdio>
    #include<cctype>
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    #define ll long long
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],stk[19],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
        void write(ll x){int top=0;while(x)stk[++top]=(x%10)+48,x/=10;while(top)Put(stk[top--]);Put('
    ');}
    }
    using namespace IO;
    int gcd(int n,int m){return !m||!n? n+m:gcd(m,n%m);}
    int t[400007];
    void build(int p,int l,int r)
    {
        if(l==r) return (void)(t[p]=read());
        build(ls,l,mid),build(rs,mid+1,r),t[p]=gcd(t[ls],t[rs]);
    }
    void update(int p,int l,int r,int x,int v)
    {
        if(l==r) return (void)(t[p]=v);
        x<=mid? update(ls,l,mid,x,v):update(rs,mid+1,r,x,v);t[p]=gcd(t[ls],t[rs]);
    }
    int Find(int p,int l,int r,int a,int b)
    {
        if(l==r) return l;
        int x=gcd(a,t[ls]),y=gcd(b,t[rs]);
        return x<=y? Find(ls,l,mid,a,y):Find(rs,mid+1,r,x,b);
    }
    ll cal1(int p,int l,int r,int x,int v)
    {
        if(l==r) return gcd(t[p],v);
        int a=gcd(t[rs],v),b=gcd(t[ls],a);
        return x<=mid? cal1(ls,l,mid,x,a):(a==b? 1ll*(mid-l+1)*a:cal1(ls,l,mid,x,a))+cal1(rs,mid+1,r,x,v);
    }
    ll cal2(int p,int l,int r,int x,int v)
    {
        if(l==r) return gcd(t[p],v);
        int a=gcd(t[ls],v),b=gcd(t[rs],a);
        return x>mid? cal2(rs,mid+1,r,x,a):(a==b? 1ll*(r-mid)*a:cal2(rs,mid+1,r,x,a))+cal2(ls,l,mid,x,v);
    }
    int main()
    {
        int n=read(),Q=read();
        build(1,1,n);
        for(int p,v;Q;--Q) p=read(),v=read(),update(1,1,n,p,v),p=Find(1,1,n,0,0),write(cal1(1,1,n,p,0)+cal2(1,1,n,p,0)-t[1]);
        return Flush(),0;
    }
    
  • 相关阅读:
    2030年的10大热门职业
    10种散发着爱情信号的肢体语言
    猎头不来找你的5种原因
    15个不得不去的“秘密”景点
    保持微笑的五大好处
    vscode 格式化突然失效
    openlayers之全屏控件的使用
    openlayers之点,线,面(以城市,河流,省份为例,分别对应点线面)
    openlayers 添加标记点击弹窗 定位图标闪烁
    搜索框focus 搜索面板显示 点击别处消失 从浏览器别的页面回来消失
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11888369.html
Copyright © 2020-2023  润新知