20260528模拟赛

20260528模拟赛

丁香之路

题面:

一张 \(n\) 个点的完全图,边 \((i,j)\) 的边权是 \(|i-j|\),给出 \(m\) 条特殊边和起点 \(S\),对于每个 \(1\leq i\leq n\) 求出从 \(S\) 出发走到 \(i\) 结束,要求至少经过每个特殊边一次,边可以重复走,路径边权和的最小值。\(n\leq 2500\)

题解:

显然除了特殊边外一定是走若干相邻点之间的边把他们连接起来,考虑这些边怎么走最少,对于一个 \(t\),初始设置 \(s\to t\) 之间的边状态为 \(1\),表示他们全都要走,然后对于每一条特殊边 \((u,v)\),反转 \(u\to v\) 之间的所有边的状态,这样是最优的因为所有这些要走的边都不交。

但是此时这些边形成了若干连通块,我们需要把这些连通块连接起来,每次链接的代价是长度乘二,直接做最小生成树就好了。

代码
    #include<bits/stdc++.h>
    #define ll long long
    #define fir first
    #define sec second
    using namespace std;
    
    inline int read(){
        int s=0,k=1;
        char c=getchar();
        while(c>'9'||c<'0'){
            if(c=='-') k=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            s=(s<<3)+(s<<1)+(c^48);
            c=getchar();
        }
        return s*k;
    }
    
    const int N=2505;
    int vis[N],a[N],b[N],n,m,S;
    ll ans;
    
    struct dsu{
        int fa[N];
    
        void init(int n){
            for(int i=1;i<=n;i++) fa[i]=i;
        }
    
        int find(int x){
            if(fa[x]==x) return x;
            else return fa[x]=find(fa[x]);
        }
    
        void merge(int x,int y){
            int fx=find(x),fy=find(y);
            if(fx==fy) return ;
            fa[fx]=fy;
        }
    }A,B;
    
    int main(){
    //    freopen(".in","r",stdin);
    //    freopen(".out","w",stdout);
        n=read();m=read();S=read();
        A.init(n);vis[S]=1;
        for(int i=1;i<=m;i++){
            int u=read(),v=read();
            if(u>v) swap(u,v);
            a[u]^=1;a[v]^=1;
            ans+=v-u;
            vis[u]=1;vis[v]=1;
            A.merge(u,v);
        }
        for(int i=1;i<=n;i++){
            for(int i=1;i<=n;i++) B.fa[i]=A.fa[i],b[i]=a[i];
            b[i]^=1;b[S]^=1;
            for(int i=1;i<=n;i++) b[i]^=b[i-1];
            ll res=ans;
            for(int i=1;i<n;i++) 
                if(b[i]){
                    res++;
                    B.merge(i,i+1);
                }
            vector<tuple<int,int,int> >vec;
            int lst=0;
            for(int j=1;j<=n;j++)
                if(vis[j]||j==i){
                    if(lst) vec.emplace_back(j-lst,lst,j);
                    lst=j;
                }
            sort(vec.begin(),vec.end());
            for(auto o:vec){
                int w,u,v;tie(w,u,v)=o;
                int fx=B.find(u),fy=B.find(v);
                if(fx!=fy){
                    B.fa[fx]=fy;
                    res+=w*2;
                }
            }
            printf("%lld ",res);
        }
        return 0;
    }

水池

题面:

有一个长条形的水池,可以划分成 \(n\) 格。其中第 \(i\) 格和 \(i+1\) 格之间相邻,由一块高度为 \(h_i\) 的可调节挡板隔开。第 \(1\) 格左侧和第 \(n\) 格右侧是无限高的池壁。初始时水池中没有水。现在进行 \(q\) 次操作,操作有以下四种:

  • \(0\ i\ x\ h\) 在第 \(x\) 格灌水直到该格的水面高度不低于 \(h\)(若当前水面高度已经达到 \(h\) 则无事发生);
  • \(1\ i\ x\) 打开第 \(x\) 格底部的排水口直到该格的水流干,再关闭排水口;
  • \(2\ i\ x\ h\) 将第 \(x\) 格右侧的挡板高度增加到 \(h\)(不改变现有水面,保证挡板高度不会下降);
  • \(3\ i\ x\) 查询第 \(x\) 格的水面高度。

其中,\(i\) 表示这次操作是基于第 \(i\) 次操作之后的情况。\(i=0\) 表示基于初始状态。也就是说,这个问题要求对操作可持续化。\(1\leq n,q\leq 200000\)

题解:

对于操作 0,是将从 \(x\) 开始向左第一块隔板高度 \(\geq h\)\(L\) 和向右第一块隔板高度 \(\leq h\)\(R\),这一区间赋值成 \(x\),但是 \(x\) 的水位若是已经大于 \(h\) 了那么就不进行操作了。对于操作 1,是将从 \(x\) 开始向左第一块隔板高度 \(\geq h\)\(L\) 和向右第一块隔板高度 \(\leq h\)\(R\),将从 \(L\)\(R\) 的每一个格子的值赋成到 \(x\) 这一路径 (区间) 隔板的最大值。

实际维护水位是困难的,但是由于每次单点询问,可以维护每个点的水位是哪个操作最终导致的,这样如果最终导致操作是 \(0\),就输出它对应的 \(h\),如果最终操作是 \(1\),就输出那个时刻区间隔板的最大值。

所以一棵线段树维护最终导致操作是什么,区间覆盖,单点求值,可持久化。

另一棵维护隔板的变化,单点修改,区间查询 \(\max\),线段树二分向两侧第一个大于 \(h\) 的位置,可持久化。

代码

    #include<bits/stdc++.h>
    #define ll long long
    #define fir first
    #define sec second
    using namespace std;
    
    inline int read(){
        int s=0,k=1;
        char c=getchar();
        while(c>'9'||c<'0'){
            if(c=='-') k=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            s=(s<<3)+(s<<1)+(c^48);
            c=getchar();
        }
        return s*k;
    }
    
    const int N=2e5+5;
    int n,Q;
    struct que{
        int op,x,v;
    }qu[N];
    
    namespace H{
        int rt[N],tot;
        struct Tree{int l,r,v;};
        vector<Tree>t(1);
    
        void pushup(int s){
            t[s].v=max(t[t[s].l].v,t[t[s].r].v);
        }
    
        int build(int l,int r){
            int s=++tot;
            t.emplace_back(Tree());
            if(l==r){
                t[s].v=read();
                return s;
            }
            int mid=l+r>>1;
            int L=build(l,mid);
            int R=build(mid+1,r);
            t[s].l=L; t[s].r=R;
            pushup(s);
            return s;
        }
        void build(){ rt[0]=build(1,n-1); }
    
        int update(int u,int l,int r,int x,int v){
            int s=++tot;
            t.emplace_back(t[u]);
            t[s].v=max(t[s].v,v);
            if(l==r) return s;
            int mid=l+r>>1,L,R;
            if(x<=mid) L=update(t[u].l,l,mid,x,v),t[s].l=L;
            else R=update(t[u].r,mid+1,r,x,v),t[s].r=R;
            return s;
        }
        void update(int i,int x,int w){
            rt[i]=update(rt[i],1,n-1,x,w);
        }
    
        int erfenl(int s,int l,int r,int x,int v){
            if(t[s].v<v) return 0;
            if(l==r) return l;
            int mid=l+r>>1,ans=0;
            if(x>mid) ans=erfenl(t[s].r,mid+1,r,x,v);
            if(ans==0) ans=erfenl(t[s].l,l,mid,x,v);
            return ans;
        }
    
        int erfenr(int s,int l,int r,int x,int v){
            if(t[s].v<v) return n+1;
            if(l==r) return l;
            int mid=l+r>>1,ans=n+1;
            if(x<=mid) ans=erfenr(t[s].l,l,mid,x,v);
            if(ans==n+1) ans=erfenr(t[s].r,mid+1,r,x,v);
            return ans;
        }
    
        pair<int,int> erfen(int i,int x,int v){
            int l,r;
            if(x==1) l=1;
            else l=erfenl(rt[i],1,n-1,x-1,v)+1;
            if(x==n) r=n;
            else r=erfenr(rt[i],1,n-1,x,v);
            return make_pair(l,r);
        }
    
        int query(int s,int l,int r,int L,int R){
            if(L<=l&&r<=R) return t[s].v;
            int mid=l+r>>1;
            if(R<=mid) return query(t[s].l,l,mid,L,R);
            if(L>mid) return query(t[s].r,mid+1,r,L,R);
            return max(query(t[s].l,l,mid,L,R),query(t[s].r,mid+1,r,L,R));
        }
        int query(int i,int L,int R){ 
            return query(rt[i],1,n-1,L,R); 
        }
    }
    
    namespace T{
        int rt[N],tot;
        struct Tree{ int l,r,v;};
        vector<Tree>t(1);
    
        int update(int u,int l,int r,int L,int R,int v){
            int s=++tot;
            t.emplace_back(t[u]);
            if(L<=l&&r<=R){
                t[s].v=v;
                return s;
            }
            int mid=l+r>>1,ls,rs;
            if(L<=mid) ls=update(t[u].l,l,mid,L,R,v),t[s].l=ls;
            if(R>mid) rs=update(t[u].r,mid+1,r,L,R,v),t[s].r=rs;
            return s;
        }
        void update(int i,int L,int R,int v){
            rt[i]=update(rt[i],1,n,L,R,v);
        }
    
        int query(int s,int l,int r,int x){
            if(l==r) return t[s].v;
            int mid=l+r>>1;
            if(x<=mid) return max(t[s].v,query(t[s].l,l,mid,x));
            else return max(t[s].v,query(t[s].r,mid+1,r,x));
        }
        int query(int i,int x){ return query(rt[i],1,n,x); }
    }
    
    int query(int rt,int x){
        int i=T::query(rt,x);
        if(i==0) return 0;
        if(qu[i].op==0) return qu[i].v;
        else{
            if(x==qu[i].x) return 0;
            int l=x,r=qu[i].x;
            if(l>r) swap(l,r);
            return H::query(i,l,r-1);
        }
    }
    
    void upd(int i,int x,int v){
        int l,r;tie(l,r)=H::erfen(i,x,v);
        T::update(i,l,r,i);
    }
    
    int main(){
    //    freopen(".in","r",stdin);
    //    freopen(".out","w",stdout);
        n=read();Q=read();
        if(n!=1) H::build();
        for(int i=1;i<=Q;i++){
            int op=read(),pre=read();
            H::rt[i]=H::rt[pre];
            T::rt[i]=T::rt[pre];
            if(op==0){
                int x=read(),v=read();
                int w=query(i,x);
                if(w<v) upd(i,x,v);
                qu[i]={op,x,v};
            }
            else if(op==1){
                int x=read();
                int v=query(i,x);
                upd(i,x,v);
                qu[i]={op,x,0};
            }
            else if(op==2){
                int x=read(),v=read();
                H::update(i,x,v);
            }
            else{
                int x=read();
                printf("%d\n",query(i,x));
            }
        }
        return 0;
    }
posted @ 2026-06-08 18:07  programmingysx  阅读(8)  评论(0)    收藏  举报
Title