牛客多校3

C.Concatenation

题意:给定n个字符串,求一个将他们拼接起来的方案,使得结果的字典序最小。

分析:对n个字符串排序,ab前面的条件是ab<ba,为什么这样正反拼接是正确的呢?在S1为S2子串的情况下,我们要考虑把谁放在前面,那就比一比谁放前面更小就可以了。

代码:

不加&会超时!不加&会超时!不加&会超时!传引用传引用传引用!!!

#include<bits/stdc++.h>
using namespace std;

const int N=2e6+6;
int T,n,a[N];
string s[N];

int cmp(string &a, string &b) 
{
    string s1 = a + b, s2 = b + a;
    return s1 < s2;
}

int main()
{
	cin>>n;
	for( int i=1; i<=n; ++i )     cin>>s[i];
	sort(s + 1, s + n + 1, cmp);
    for(int i = 1; i <= n; i++)   cout << s[i];
	return 0;
}

A.Ancestor

题意:给出两棵编号为1~n的树A和B,A、B树上每个节点均有一个权值,给出k个关键点的编号x1...xn,问有多少种方案使得去掉恰好一个关键点使得剩余关键点在树A上LCA的权值大于树B上LCA的权值。

分析:

       需要用到一个结论——树上多个点的LCA为这多个点中DFS序最大的点和DFS序最小的点的LCA。故可以先求出所给k个关键点的DFS序,然后枚举删去哪一个。记得枚举前预处理LCA,要不然会超时。预处理其实只用求3+3次就可以了,分别为:删掉A的DFS最小(Ahead),删掉A的DFS序最大(Atail),删掉A的DFS序中间元素。

        枚举每个点的时候 if-else 判断一下该点在A、B树中的地位即可。

代码:

(有点长,主要是因为A、B两棵树形态不同,所以需要分开求。)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int MAXN=105000;
int N,K,x,ans=0;
int d1,d2;
int w1[MAXN],w2[MAXN]; //存两棵树每个点的weight
int key[MAXN];//题目中提到的K个key number
int ds1[MAXN],ds2[MAXN];// 存dfs序  dfs sort
int Log2[MAXN],faA[MAXN][30],faB[MAXN][30],depA[MAXN]={0},depB[MAXN]={0};//找LCA需要的一些数组
bool visA[MAXN]={false},visB[MAXN]={false};//找LCA需要的一些数组
vector< vector<int> > treeA,treeB;//存树
vector< pair<int,int> > KDS1,KDS2;//第一个数存顶点的dfs序,第二个数存顶点编号

void TOinput()
{
    for(int i=1;i<=K;i++)  cin>>key[i];
    for(int i=1;i<=N;i++)  cin>>w1[i];
    for(int i=2;i<=N;i++)
    {
        cin>>x;
        treeA[x].push_back(i);
        treeA[i].push_back(x);
    }
    for(int i=1;i<=N;i++)  cin>>w2[i];
    for(int i=2;i<=N;i++)
    {
        cin>>x;
        treeB[x].push_back(i);
        treeB[i].push_back(x);
    }
}

void do_pre()
{
    Log2[1] = 0;
    for (int i = 2; i <= N; ++i)
    Log2[i] = Log2[i / 2] + 1;
}

void dfsA(int cur, int fath)
{
    if (visA[cur]) return;

    visA[cur] = true;
    depA[cur] = depA[fath] + 1;
    faA[cur][0] = fath;
    ds1[cur]=d1++;
    
    for (int i = 1; i <= Log2[depA[cur]]; i++)  faA[cur][i] = faA[faA[cur][i - 1]][i - 1];

    for (int i=0; i<treeA[cur].size();i++)
        dfsA(treeA[cur][i], cur);
}


void dfsB(int cur, int fath)
{
    if (visB[cur]) return;

    visB[cur] = true;
    depB[cur] = depB[fath] + 1;
    faB[cur][0] = fath;
    ds2[cur]=d2++;
    
    for (int i = 1; i <= Log2[depB[cur]]; i++)  faB[cur][i] = faB[faB[cur][i - 1]][i - 1];

    for (int i=0; i<treeB[cur].size();i++)
        dfsB(treeB[cur][i], cur);
}


int lcaAA(int a, int b)
{
    if (depA[a] > depA[b])  swap(a, b);
    while (depA[a] != depA[b]) b = faA[b][Log2[depA[b] - depA[a]]];

    if (a == b)  return a;
    for (int k = Log2[depA[a]]; k >= 0; k--)
    {
        if (faA[a][k] != faA[b][k])  a = faA[a][k], b = faA[b][k];
    }
    return faA[a][0];
}

int lcaBB(int a, int b)
{
    if (depB[a] > depB[b])  swap(a, b);
    while (depB[a] != depB[b]) b = faB[b][Log2[depB[b] - depB[a]]];

    if (a == b)  return a;
    for (int k = Log2[depB[a]]; k >= 0; k--)
    {
        if (faB[a][k] != faB[b][k])  a = faB[a][k], b = faB[b][k];
    }
    return faB[a][0];
}

void TOdelete()
{
    sort(KDS1.begin(),KDS1.end());
    sort(KDS2.begin(),KDS2.end());
    int Ahead=KDS1[0].second,Atail=KDS1[K-1].second,Bhead=KDS2[0].second,Btail=KDS2[K-1].second;
    int A1,A2,A3,B1,B2,B3;
    A1=lcaAA(KDS1[1].second,Atail);//头被删了
    A2=lcaAA(Ahead,KDS1[K-2].second);//尾巴被删了
    A3=lcaAA(Ahead,Atail);//删的是中间的
    B1=lcaBB(KDS2[1].second,Btail);
    B2=lcaBB(Bhead,KDS2[K-2].second);
    B3=lcaBB(Bhead,Btail);

    for(int i=1;i<=K;i++)
    {
        int lcaA,lcaB;
        if(key[i]==Ahead)   lcaA=A1;
        if(key[i]==Atail)   lcaA=A2;
        if(key[i]!=Ahead && key[i]!=Atail)  lcaA=A3;

        if(key[i]==Bhead)   lcaB=B1;
        if(key[i]==Btail)   lcaB=B2;
        if(key[i]!=Bhead && key[i]!=Btail)  lcaB=B3; 

        if(w1[lcaA]>w2[lcaB]) ans++;
    }    
}


int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin>>N>>K;
    treeA.resize(N+10);  
    treeB.resize(N+10); 

    TOinput();
    do_pre();
    d1=1; d2=1;
    dfsA(1,0);  for(int i=1;i<=K;i++) KDS1.push_back({ds1[key[i]],key[i]}); //把通过dfs得到的字典序存进去
    dfsB(1,0);  for(int i=1;i<=K;i++) KDS2.push_back({ds2[key[i]],key[i]});

    TOdelete();//枚举 删去哪一个key number点

    cout<<ans;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值