2022牛客暑期多校训练营3(总结+补题)

总结:

好消息:队伍过了4题rk100出头;

坏消息:我过了0题。

题解:

A - Ancestor

题意:

给你两棵以 1 1 1 为根的 n n n 个点的树 a , b a,b a,b a , b a,b a,b 树中的每个点都有一个点权,再给你 m m m 个点 c i ( 1 ≤ i ≤ n ) c_i(1\le i\le n) ci(1in) ,问:每次从 a a a 树和 b b b 树中删除一个 m m m 个点中的点 c i c_i ci ,问 a , b a ,b a,b 树剩余 m − 1 m-1 m1 个点中公共祖先的点权满足 a > b a>b a>b 的数量是多少。

做法:

对于点集 c c c ,我们可以分别对 a a a 树和 b b b 树中的点集 c c c 做一次前缀 l c a lca lca 以及后缀 l c a lca lca ,对于每个 c i c_i ci ,我们只需要判断 a [ l c a ( p r e a [ i − 1 ] , s u f a [ i + 1 ] ) ] a[lca(prea[i-1],sufa[i+1])] a[lca(prea[i1],sufa[i+1])] 是否大于 b [ l c a ( p r e b [ i − 1 ] , s u f b [ i + 1 ] ) ] b[lca(preb[i-1],sufb[i+1])] b[lca(preb[i1],sufb[i+1])] ,是则 a n s ans ans++ ,最后输出答案即可。

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
struct slpf{
    const int nn;
    vector<int> fa,dep,son,siz,top,dfn,w;
    vector<int> v;
    vector<vector<int>> g;
    int tim;
    slpf(int n1):nn(n1),fa(n1+1),dep(n1+1),son(n1+1,0),siz(n1+1),top(n1+1),dfn(n1+1),w(n1+1),v(n1+1),g(n1+1),tim(0){}
    void add(int uu,int vv)
    {
        g[uu].push_back(vv);
    }
    void dfs1(int now,int fr)
    {
        fa[now]=fr;
        dep[now]=dep[fr]+1;
        siz[now]=1;
        int max_size=-1;
        for(int x:g[now])
        {
            if(x==fr)
                continue;
            dfs1(x,now);
            siz[now]+=siz[x];
            if(siz[x]>max_size)
            {
                max_size=siz[x];
                son[now]=x;
            }
        }
    }
    void dfs2(int now,int tp)
    {
        dfn[now]=++tim;
        top[now]=tp;
        w[tim]=v[now];
        if(!son[now])
            return;
        dfs2(son[now],tp);
        for(int x:g[now])
        {
            if(x==fa[now]||x==son[now])
                continue;
            dfs2(x,x);
        }
    }
    void make_tree(int root,vector<int> &arr)
    {
        v=arr;
        dfs1(root,root);
        dfs2(root,root);
        // build(1,1,nn);
    }
    int lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>=dep[top[y]])
                x=fa[top[x]];
            else
                y=fa[top[y]];
        }
        return dep[x]<dep[y]?x:y;
    }
};
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    vector<int> c(m+2);
    vector<int> a(n+1),b(n+1);
    for(int i=1;i<=m;i++)
        cin>>c[i];
    slpf tr1(n),tr2(n);
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=2;i<=n;i++)
    {
        cin>>k;
        tr1.add(k,i);
    }
    for(int i=1;i<=n;i++)
        cin>>b[i];
    for(int i=2;i<=n;i++)
    {
        cin>>k;
        tr2.add(k,i);
    }
    tr1.make_tree(1,a);
    tr2.make_tree(1,b);
    vector<int> pre1(m+1),pre2(m+1);
    vector<int> suf1(m+1),suf2(m+1);
    pre1[1]=pre2[1]=c[1];
    suf1[m]=suf2[m]=c[m];
    for(int i=2;i<=m;i++)
    {
        pre1[i]=tr1.lca(pre1[i-1],c[i]);
        pre2[i]=tr2.lca(pre2[i-1],c[i]);
    }
    for(int i=m-1;i>=1;i--)
    {
        suf1[i]=tr1.lca(suf1[i+1],c[i]);
        suf2[i]=tr2.lca(suf2[i+1],c[i]);
    }
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        if(i==1)
        {
            if(a[suf1[i+1]]>b[suf2[i+1]])
                ans++;
        }
        else if(i==m)
        {
            if(a[pre1[i-1]]>b[pre2[i-1]])
                ans++;
        }
        else
        {
            if(a[tr1.lca(pre1[i-1],suf1[i+1])]>b[tr2.lca(pre2[i-1],suf2[i+1])])
                ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

C - Concatenation

题意:

给你 n n n 个字符串,要求你把 n n n 个字符串按字典序最小的方式连接起来并输出.

做法:

手写 c m p cmp cmp 函数,排序后输出即可.

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n;
    vector<string> a(n);
    for(auto &x:a)
        cin>>x;
    auto cmp = [&](string& aa,string bb)   
    {
        return aa+bb<bb+aa;
    };
    sort(a.begin(),a.end(),cmp);
    for(auto x:a)
        cout<<x;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值