2023.1.13模拟赛总结

2023.1.13模拟赛总结

实质上是阶段性学习检测。

T1:线段树

直接建一棵区间为1~m的线段树,每插入一点就将该点值修改,维护区间最大值。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 200005
#define INF INT_MAX
LL m,d,n;
struct node{
    LL l,r,maxn;
}tr[MAXN*4];
void pushup(LL rt){
    if(tr[rt].l!=tr[rt].r){
        tr[rt].maxn=max(tr[rt<<1].maxn,tr[rt<<1|1].maxn);
    }
}
void build(LL rt,LL l,LL r){
    tr[rt].l=l;tr[rt].r=r;
    if(l==r){
        tr[rt].maxn=0;
        return ;
    }
    LL mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
void update(LL rt,LL l,LL r,LL val){
    if(tr[rt].l>r||tr[rt].r<l){
        return ;
    }else if(tr[rt].l>=l&&tr[rt].r<=r){
        tr[rt].maxn=max(tr[rt].maxn,val);
        return ;
    }else{
        update(rt<<1,l,r,val);
        update(rt<<1|1,l,r,val);
        pushup(rt);
    }
}
LL query(LL rt,LL l,LL r){
    if(tr[rt].l>r||tr[rt].r<l)return -INF;
    else if(tr[rt].l>=l&&tr[rt].r<=r){
        pushup(rt);
        return tr[rt].maxn;
    }else{
        pushup(rt);
        return max(query(rt<<1,l,r),query(rt<<1|1,l,r));
    }
}
int main(){
    scanf("%lld%lld",&m,&d);
    LL t=0;
    build(1,1,m);
    while(m--){
        char ch;
        while(1){
            scanf("%c",&ch);
            if(ch=='A'||ch=='Q')break;
        }
        if(ch=='Q'){
            LL l;
            scanf("%lld",&l);
            t=query(1,n-l+1,n);
            printf("%lld\n",t);
        }else if(ch=='A'){
            LL x;
            scanf("%lld",&x);
            x=(x+t)%d;
            n++;
            update(1,n,n,x);
        }
    }
}

T2:树链剖分

经典树剖,修改路径上的点,统计子树总和(此处注意子树节点实质上编号是在一起的,可以线段树区间修改)。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 1000005
#define INF INT_MAX
LL n,q;
vector<LL>a[MAXN];
void add(LL u,LL v){
    a[u].push_back(v);
}
struct node{
    LL l,r,val,lazy;
}tr[MAXN*4];
LL siz[MAXN],fa[MAXN],son[MAXN],dep[MAXN];
void dfs1(LL x){
    siz[x]=1;dep[x]=dep[fa[x]]+1;
    for(LL i=0;i<a[x].size();i++){
        LL xx=a[x][i];
        if(xx==fa[x])continue;
        fa[xx]=x;
        dfs1(xx);
        siz[x]+=siz[xx];
        if(siz[xx]>siz[son[x]])son[x]=xx;
    }
}
LL top[MAXN],p[MAXN],fp[MAXN],pos;
void dfs2(LL x,LL xtop){
    top[x]=xtop;p[x]=++pos;fp[pos]=x;
    if(son[x])dfs2(son[x],xtop);
    for(LL i=0;i<a[x].size();i++){
        LL xx=a[x][i];
        if(xx==son[x]||xx==fa[x])continue;
        dfs2(xx,xx);
    }
}
void build(LL rt,LL l,LL r){
    tr[rt].l=l;tr[rt].r=r;tr[rt].val=0;
    if(l==r){
        return ;
    }
    LL mid=(l+r)>>1;
    build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
}
void pushup(LL rt){
    if(tr[rt].l!=tr[rt].r){
        tr[rt].val=tr[rt<<1].val+tr[rt<<1|1].val;
    }
}
void pushdown(LL rt){
    if(tr[rt].lazy){
        tr[rt<<1].lazy+=tr[rt].lazy;
        tr[rt<<1|1].lazy+=tr[rt].lazy;
        tr[rt<<1].val+=tr[rt].lazy*(tr[rt<<1].r-tr[rt<<1].l+1);
        tr[rt<<1|1].val+=tr[rt].lazy*(tr[rt<<1|1].r-tr[rt<<1|1].l+1);
        tr[rt].lazy=0;
    }
}
void update_(LL rt,LL l,LL r,LL d){
    pushdown(rt);
    if(tr[rt].l>r||tr[rt].r<l)return ;
    else if(tr[rt].l>=l&&tr[rt].r<=r){
        tr[rt].val+=d*(tr[rt].r-tr[rt].l+1);tr[rt].lazy+=d;
        return ;
    }else{
        update_(rt<<1,l,r,d);
        update_(rt<<1|1,l,r,d);
        pushup(rt);
    }
}
void update(LL u,LL v,LL d){
    LL f1=top[u],f2=top[v];
    while(f1!=f2){
        if(dep[f1]<dep[f2]){
            swap(f1,f2);swap(u,v);
        }
        update_(1,p[f1],p[u],d);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update_(1,p[u],p[v],d);
    return ;
}
LL query(LL rt,LL l,LL r){
    pushdown(rt);pushup(rt);
    if(tr[rt].l>r||tr[rt].r<l)return 0;
    else if(tr[rt].l>=l&&tr[rt].r<=r){
        return tr[rt].val;
    }else{
        return query(rt<<1,l,r)+query(rt<<1|1,l,r);
    }
}
int main(){
    scanf("%lld",&n);
    for(LL i=1;i<n;i++){
        LL u,v;
        scanf("%lld%lld",&u,&v);
        u++;v++;
        add(u,v);
    }
    dfs1(1);dfs2(1,1);build(1,1,n);
    scanf("%lld",&q);
    while(q--){
        char ch[15];
        scanf("%s",ch);
        if(ch[0]=='A'){
            LL u,v,d;
            scanf("%lld%lld%lld",&u,&v,&d);
            u++;v++;
            update(u,v,d);
        }else if(ch[0]=='Q'){
            LL u;
            scanf("%lld",&u);
            u++;
            printf("%lld\n",query(1,p[u],p[u]+siz[u]-1));
        }
    }
}

T3:线段树

经典操作,维护区间最大连续子段和,单点修改。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 500005
#define INF INT_MAX
struct node{
    LL l,r,val;
    LL lson,rson,maxn;
}tr[MAXN*4];
LL n,m;
LL a[MAXN];
void pushup(LL rt){
    if(tr[rt].l!=tr[rt].r){
        tr[rt].val=tr[rt<<1].val+tr[rt<<1|1].val;
        tr[rt].lson=max(tr[rt<<1].lson,tr[rt<<1].val+tr[rt<<1|1].lson);
        tr[rt].rson=max(tr[rt<<1|1].rson,tr[rt<<1|1].val+tr[rt<<1].rson);
        tr[rt].maxn=max(tr[rt<<1].maxn,tr[rt<<1|1].maxn);
        tr[rt].maxn=max(tr[rt].maxn,tr[rt<<1].rson+tr[rt<<1|1].lson);
        tr[rt].maxn=max(tr[rt].maxn,max(tr[rt].lson,tr[rt].rson));
    }
}
void build(LL rt,LL l,LL r){
    tr[rt].l=l;tr[rt].r=r;
    if(l==r){
        tr[rt].val=a[l];
        tr[rt].lson=tr[rt].rson=a[l];
        tr[rt].maxn=a[l];
        return ;
    }
    LL mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
void update(LL rt,LL p,LL s){
    if(tr[rt].l==p&&tr[rt].r==p){
        tr[rt].val=s;
        tr[rt].lson=tr[rt].rson=s;
        tr[rt].maxn=s;
        return ;
    }else{
        LL mid=(tr[rt].l+tr[rt].r)>>1;
        if(p>mid)update(rt<<1|1,p,s);
        else if(p<=mid)update(rt<<1,p,s);
        pushup(rt);
    }
}
node query(LL rt,LL l,LL r){
    if(tr[rt].l>=l&&tr[rt].r<=r){
        return tr[rt];
    }else{
        LL mid=(tr[rt].l+tr[rt].r)>>1;
        if(r<=mid)return query(rt<<1,l,r);
        else if(l>mid)return query(rt<<1|1,l,r);
        else{
            node t,a=query(rt<<1,l,r),b=query(rt<<1|1,l,r);
            t.lson=max(a.lson,a.val+b.lson);
            t.rson=max(b.rson,b.val+a.rson);
            t.maxn=max(max(a.maxn,b.maxn),a.rson+b.lson);
            return t;
        }
    }
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    build(1,1,n);
    while(m--){
        LL k;
        scanf("%lld",&k);
        if(k==1){
            LL l,r;
            scanf("%lld%lld",&l,&r);
            if(l>r)swap(l,r);
            printf("%lld\n",query(1,l,r).maxn);
        }else if(k==2){
            LL p,s;
            scanf("%lld%lld",&p,&s);
            update(1,p,s);
        }
    }
}

T4:平衡树

区间翻转,区间修改,区间最大值查询。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 100005
#define INF INT_MAX
LL n,m;
struct node{
    LL size,pri,val,lazy,rot,ch[2],maxn;
}tr[MAXN*4];
LL rt,root1,root2;
inline void pushup(LL rt){
    tr[rt].size=tr[tr[rt].ch[0]].size+tr[tr[rt].ch[1]].size+1;
    tr[rt].maxn=tr[rt].val;
    if(tr[rt].ch[0])tr[rt].maxn=max(tr[rt].maxn,tr[tr[rt].ch[0]].maxn);
    if(tr[rt].ch[1])tr[rt].maxn=max(tr[rt].maxn,tr[tr[rt].ch[1]].maxn);
}
inline void pushdown(LL rt){
    if(tr[rt].rot){
        if(tr[rt].ch[0])tr[tr[rt].ch[0]].rot^=1;
        if(tr[rt].ch[1])tr[tr[rt].ch[1]].rot^=1;
        swap(tr[rt].ch[0],tr[rt].ch[1]);
        tr[rt].rot=0;
    }
    if(tr[rt].lazy){
        if(tr[rt].ch[0]){
            tr[tr[rt].ch[0]].lazy+=tr[rt].lazy;
            tr[tr[rt].ch[0]].val+=tr[rt].lazy;
            tr[tr[rt].ch[0]].maxn+=tr[rt].lazy;
        }
        if(tr[rt].ch[1]){
            tr[tr[rt].ch[1]].lazy+=tr[rt].lazy;
            tr[tr[rt].ch[1]].val+=tr[rt].lazy;
            tr[tr[rt].ch[1]].maxn+=tr[rt].lazy;
        }
        tr[rt].lazy=0;
        pushup(rt);
    }
}
LL merge(LL x,LL y){
    LL now;
    pushdown(x);pushdown(y);
    if(!x||!y)return x+y;
    if(tr[x].pri<tr[y].pri){
        now=x;tr[x].ch[1]=merge(tr[x].ch[1],y);
    }else{
        now=y;tr[y].ch[0]=merge(x,tr[y].ch[0]);
    }
    pushup(now);return now;
}
void split(LL rt,LL &x,LL &y,LL val){
    if(!rt){x=y=0;return ;}
    pushdown(rt);
    if(tr[tr[rt].ch[0]].size>=val)y=rt,split(tr[rt].ch[0],x,tr[y].ch[0],val);
    else x=rt,split(tr[rt].ch[1],tr[x].ch[1],y,val-tr[tr[rt].ch[0]].size-1);
    pushup(rt);
}
LL tot;
inline void insert(LL val){
    tr[++tot].pri=rand();
    tr[tot].val=val;
    tr[tot].maxn=val;
    tr[tot].size=1;
    rt=merge(rt,tot);
}
inline void update1(LL l,LL r,LL val){
    LL x,y,z;
    split(rt,x,y,l-1);
    split(y,y,z,r-l+1);
    tr[y].maxn+=val;
    tr[y].val+=val;
    tr[y].lazy+=val;
    rt=merge(merge(x,y),z);
}
inline void update2(LL l,LL r){
    LL x,y,z;
    split(rt,x,y,l-1);
    split(y,y,z,r-l+1);
    tr[y].rot^=1;
    rt=merge(merge(x,y),z);
}
inline void query(LL l,LL r){
    LL x,y,z;
    split(rt,x,y,l-1);
    split(y,y,z,r-l+1);
    printf("%lld\n",tr[y].maxn);
    rt=merge(merge(x,y),z);
}
int main(){
    srand(time(0));
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=n;i++){
        insert(0);
    }
    while(m--){
        LL opt;
        scanf("%lld",&opt);
        if(opt==1){
            LL l,r,x;
            scanf("%lld%lld%lld",&l,&r,&x);
            update1(l,r,x);
        }else if(opt==2){
            LL l,r;
            scanf("%lld%lld",&l,&r);
            update2(l,r);
        }else if(opt==3){
            LL l,r;
            scanf("%lld%lld",&l,&r);
            query(l,r);
        }
    }
}

T5:莫比乌斯反演、递推

虽然是莫反题,但是递推是可以搞的。

先对 l l l h h h作如下处理

1.如果 l l l k k k的倍数, l l l变为 l k \dfrac{l}{k} kl;如果不是,则变为 ⌊ l k ⌋ + 1 \left\lfloor\dfrac{l}{k}\right\rfloor+1 kl+1.

2.将 h h h变为 ⌊ h k ⌋ \left\lfloor\dfrac{h}{k}\right\rfloor kh.

这样,我们就把问题转化为了求在现在的 l l l h h h之间选 n n n个数,使得最大公约数刚好为 1 1 1的方案数。

f [ i ] f[i] f[i]为最大公约数为 i i i时的方案数(此时选出的 n n n个数不全相同), s s s为区间内 i i i的倍数个数,容易得到 f [ i ] = s n − s f[i]=s^n-s f[i]=sns.

但这之中还有些最大公约数不为 i i i的情况没减掉,且这些情况的最大公约数为 2 i 2i 2i 3 i 3i 3i 4 i 4i 4i……,我们就可以减去这些情况,得到最终的结果。

此处注意, l = 1 l=1 l=1的时候可以所有的数都选 1 1 1,所以答案要加一。

答案即为 f [ 1 ] − f [ 2 ] − f [ 3 ] f[1]-f[2]-f[3] f[1]f[2]f[3]……直到把区间内所有情况减完。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod=1000000007;
LL f[100005];
LL ksm(LL x,LL y){
    LL res=1;
    while(y){
        if(y&1){
            res=res*x%mod;
        }
        y>>=1;x=x*x%mod;
    }
    return res;
}
int main(){
    LL n,k,l,h;
    cin>>n>>k>>l>>h;
    if(l%k==0){
        l=l/k;
    }else{
        l=l/k+1;
    }
    h=h/k;
    LL s=h-l;
    for(LL i=1;i<=s;i++){
        LL L=l,R=h;
        if(L%i==0)L=L/i;
        else L=L/i+1;
        R=R/i;
        if(L>R)continue;
        LL x=R-L+1;
        f[i]=ksm(x,n)-x;
        f[i]=(f[i]+mod)%mod;
    }
    LL ans=0;
    for(LL i=s;i;i--){
        for(LL j=i*2;j<=s;j+=i){
            f[i]=(f[i]-f[j]+mod)%mod;
        }
    }
    ans=f[1];
    if(l==1)ans++;
    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值