『模拟赛』暑假集训CSP提高模拟21

Rank

意外地还凑合,本来以为这场要 GG 了。

image

A. 黎明与萤火

原[CF963B] Destruction of a Tree

签,勉强签了。

开始脑子乱,胡乱打了一个含有 3 个 dfs 函数,每个函数里含两次遍历链式前向星,不负众望大样例 T 了。

后来也是摸着摸着就出正解了,先一遍 dfs 跑出基本的数据,然后再一遍 dfs 从叶子结点开始能删就删,删边操作单独进一个 dfs,最终判断能不能全删,然后输出就行了。

点击查看代码

已经优化很多了。。

#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=2e5+5;
const int mod=998244353;
int n;
int fx[N],hh[N],to[N<<1],ne[N<<1],cnt;
int dfn[N],dff,pos[N],ans[N],siz[N],tot,rd[N];
bool yz[N];
namespace Wisadel
{
    void Wadd(int u,int v)
    {
        to[++cnt]=v;
        ne[cnt]=hh[u];
        hh[u]=cnt;
    }
    void Wdfs(int u,int fa)
    {
        siz[u]=(fa!=0);
        fx[u]=fa;
        dfn[u]=++dff;
        pos[dff]=u;
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(v==fa) continue;
            Wdfs(v,u);
            siz[u]+=1;
        }
    }
    void Wsol(int u,int fa)
    {
        if(siz[u]&1) return;
        if(yz[u]) return;
        yz[u]=1,ans[++tot]=u;
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(yz[v]) continue;
            if(v==fa){siz[v]--;continue;}
            siz[v]--;
            Wsol(v,u);
        }
    }
    void Wdfss(int u,int fa)
    {
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(v==fa) continue;
            Wdfss(v,u);
        }
        Wsol(u,fa);
    }
    short main()
    {
        n=qr; memset(hh,-1,sizeof hh); bool task=1;
        fo(i,1,n) 
        {
            int x=qr; if(!x) continue;
            Wadd(x,i),Wadd(i,x);
            rd[i]++,rd[x]++;
            if(rd[i]>2||rd[x]>2) task=0;
        }
        if(task)
        {
            if(n%2==0){printf("NO\n");return Ratio;}
            printf("YES\n");
            int st;
            fo(i,1,n) if(rd[i]<2){st=i;break;}
            Wdfs(st,0);
            fo(i,1,n) if(i%2==0) printf("%d\n",pos[i]),yz[i]=1;
            fo(i,1,n) if(!yz[i]) printf("%d\n",pos[i]);
            return Ratio;
        }
        Wdfs(1,0);
        Wdfss(1,0);
        if(tot!=n) printf("NO\n");
        else
        {
            printf("YES\n");
            fo(i,1,tot) printf("%d\n",ans[i]);
        }
        return Ratio;
    }
}
int main(){return Wisadel::main();}

B. Darling Dance

原[CF1076D] Edge Deletion

小水题,但保龄。

赛时想先进行一遍 Dijkstra,记录每个点的最短路由哪些边更新来,然后最后汇总,选更新次数多的。但一这个做法本身就有漏洞,二我没判 \(k\ge m\) 的情况,所以前面 WA 后面 RE。

正解是最短路径树,即用 \(n-1\) 条边使所有的点到根节点的距离尽可能小,恰好符合本题题意。由于最终结果是一棵树,所以除根节点外,每个结点恰好对应一条边,那么只要记一下每个点是由哪条边更新而来的,最后 dfs 输出即可。

点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=3e5+5;
const int mod=998244353;
int n,m,k,tot;
int hh[N],to[N<<1],ne[N<<1],id[N<<1],cnt;
ll w[N<<1],dis[N];
int ans[N];
bool yz[N];
struct rmm
{
    int to;ll w;
    bool operator<(const rmm & a) const 
    {
        return w>a.w;
    }
};
namespace Wisadel
{
    void Wadd(int _,int __,int ___,int i)
    {
        to[++cnt]=__;
        w[cnt]=___;
        id[cnt]=i;
        ne[cnt]=hh[_];
        hh[_]=cnt;
    }
    void Wdij(int x)
    {
        priority_queue<rmm>q;
        memset(dis,0x3f,sizeof dis);
        dis[x]=0;q.push({x,0});
        while(q.size())
        {
            int _=q.top().to;q.pop();
            if(yz[_]) continue;
            yz[_]=1;
            for(int i=hh[_];i!=-1;i=ne[i])
            {
                int __=to[i];
                if(dis[__]>=dis[_]+w[i])
                {
                    dis[__]=dis[_]+w[i];
                    q.push({__,dis[__]});
                    ans[__]=id[i];
                }
            }
        }
    }
    void Wdfs(int _)
    {
        for(int i=hh[_];i!=-1;i=ne[i])
        {
            int __=to[i];
            if(id[i]==ans[__])
            {
                if(++tot>k||tot==n) exit(0);
                printf("%d ",id[i]);
                Wdfs(__);
            }
        }
    }
    short main()
    {
        n=qr,m=qr,k=qr;
        memset(hh,-1,sizeof hh);
        fo(i,1,m)
        {
            int _=qr,__=qr,___=qr;
            Wadd(_,__,___,i),Wadd(__,_,___,i);
        }
        Wdij(1);
        printf("%d\n",k>n-1?n-1:k);
        Wdfs(1);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

C. Non-breath oblige

原[Ynoi2012] NOIP2015 充满了希望

还上 Ynoi 逝罢。

赛时只打出 \(\mathcal{O(nq)}\) 暴力和没有操作 2 那送的 20pts。

考虑由于出现操作 2 之前原序列不会有值,所以开线段树记录最后一次操作 2 的时间戳,每个操作就是简单的单点查询+修改,区间修改和单点查询。

将所有询问区间离线下来,对 r 做扫描线,遇到操作三就在 \(t_i\) 加上 \(v_{t_i}\) 并更新前缀,然后询问求后缀和即可,用树状数组维护,时间复杂度为 \(\mathcal{O(q\log n)}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
const int Ratio=0;
const int N=1e6+5;
const int mod=998244353;
int n,m,qq;
int op[N],x[N],y[N],va[N];
int t[N<<2];
ll ans[N],sum[N];
vector<pair<int,int> >q[N];
namespace Wisadel
{
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define mid ((l+r)>>1)
    inline void Wpushdown(int rt)
    {
        t[ls]=t[rs]=t[rt];
        t[rt]=0;
    }
    inline void Wupd(int rt,int l,int r,int x,int y,int k)
    {
        if(x<=l&&r<=y){t[rt]=k;return;}
        if(t[rt]) Wpushdown(rt);
        if(x<=mid) Wupd(ls,l,mid,x,y,k);
        if(y>mid) Wupd(rs,mid+1,r,x,y,k);
    }
    inline int Wq(int rt,int l,int r,int x)
    {
        if(l==r||t[rt]) return t[rt];
        if(x<=mid) return Wq(ls,l,mid,x);
        else return Wq(rs,mid+1,r,x);
    }
    inline void Wadd(int x,int va)
    {
        if(!x) return;
        while(x<=m) sum[x]+=va,x+=x&-x;
    }
    inline ll Wgsum(int x)
    {
        if(x<1) return 0;
        ll res=0;
        while(x) res+=sum[x],x^=x&-x;
        return res;
    }
    short main()
    {
        // freopen(".in","r",stdin),freopen(".out","w",stdout);
        n=qr,m=qr,qq=qr;
        fo(i,1,m)
        {
            op[i]=qr;
            if(op[i]==1)
            {
                x[i]=qr,y[i]=qr;
                int aa=Wq(1,1,n,x[i]),bb=Wq(1,1,n,y[i]);
                Wupd(1,1,n,x[i],x[i],bb),Wupd(1,1,n,y[i],y[i],aa);
            }
            else if(op[i]==2)
            {
                x[i]=qr,y[i]=qr,va[i]=qr;
                Wupd(1,1,n,x[i],y[i],i);
            }
            else
            {
                x[i]=qr;
                y[i]=Wq(1,1,n,x[i]);
            }
        }
        fo(i,1,qq)
        {
            int l=qr,r=qr;
            q[r].emplace_back(make_pair(l,i));
        }
        fo(i,1,m)
        {
            if(op[i]==3) Wadd(y[i],va[y[i]]);
            for(auto j:q[i]) ans[j.se]=Wgsum(i)-Wgsum(j.fi-1);
        }
        fo(i,1,qq) printf("%lld\n",ans[i]);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

D. 妄想感伤代偿联盟

做法好像还挺多,但是做到这时已经没啥心情打暴力了,然后直接糊了个超级 substr 上去,喜提保龄。

仍然很好题目背景,不过你都把歌曲名和歌词打出来了不放给我们听听真的合适吗qwq

赛时本来以为 T1 A不了 T2 能 A 的,结果刚好反了。因为打 T1 的时候脑子就很乱,胡乱交了个跑不过大样例的代码就去看后面的暴力了,后来强迫自己找性质结果莫名找出来了,但写得过于暴力一个代码 4 个 dfs 再加上 sb checker 乱报自测结果所以感觉拿不满,(事实上 CF 确实 WA 了一个小点

T2 想到了只跑一遍 Dijkstra 的做法,爽飞了,大样例随便跑,sb checker 莫名报 UKE,但由于 T1 的前车之鉴我并不太信这个玩意,结果是经过赛后和 GGrun 的交谈发现是做法假了。

T3 昨天找题时看到过,但没多想(正常人都不会多想的吧,好在没挂分。

下午的锣鼓 Div1 继续挂挂挂,混个 rk73,有没有有经验的佬说一下等级分 1700 这个勾式排名会扣多少分。


完结撒花~

posted @ 2024-08-15 20:11  DrRatio  阅读(42)  评论(0编辑  收藏  举报