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

时间:2019-11-19
本文章向大家介绍LOJ576 「LibreOJ NOI Round #2」签到游戏,主要包括LOJ576 「LibreOJ NOI Round #2」签到游戏使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目
先进行一个转化:
每次花费\(\gcd\limits_{i=l+1}^rB_i\)的代价,可以连\((l,r)\)这一条边。
然后我们需要求\(0\sim n\)的最小生成树。
根据Kruskal的思想,\((0,n)\)这条边一定会被选。
然后根据Prim的思想,对于某个点,我们需要找到其最短的出边。
而显然对于\(i\),它最短的出边为\((i,0)\)或者\((i,n)\)。边权为\(L_i=\gcd\limits_{j=1}^iB_j\)\(R_i=\gcd\limits_{j=i+1}^nB_j\)
显然\(L_i\)是单调不增,\(R_i\)是单调不减的。
所以\(\exists p\in[0,n),\forall i\in[0,p],R_i\le L_i,\forall i\in(p,n),L_i\le R_i\)
我们可以用线段树维护每个区间\([l,r]\)\(\gcd\limits_{i=l+1}^rB_i\),然后在线段树上二分求出\(p\)
而题目所给的修改可以直接单点修改。
剩下的就是求\(\sum\limits_{i=0}^pR_i+\sum\limits_{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('\n');}
}
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;
}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11888369.html