牛客小白月赛6

C(挑花)(dfs或bfs)

链接:https://www.nowcoder.com/acm/contest/136/C
来源:牛客网
 

题目描述

    桃花一簇开无主,可爱深红映浅红。

                                        ——《题百叶桃花》

    桃花长在桃树上,树的每个节点有一个桃花,调皮的HtBest想摘尽可能多的桃花。HtBest有一个魔法棒,摘到树上任意一条链上的所有桃花,由于HtBest法力有限,只能使用一次魔法棒,请求出Htbest最多可以摘到多少个桃花。

输入描述:

第一行有一个正整数n,表示桃树的节点个数。
接下来n-1行,第i行两个正整数ai,bi ,表示桃树上的节点ai,bi之间有一条边。

输出描述:

第一行一个整数,表示HtBest使用一次魔法棒最多可以摘到多少桃花。

示例1

输入

复制

3
1 2
2 3

输出

复制

3

示例2

输入

复制

3
1 2
1 3

输出

复制

3

示例3

输入

复制

4
1 2
2 3
3 4

输出

复制

4

备注:

对于100%的测试数据:
1 ≤ n ≤ 1000000
数据量较大,注意使用更快的输入输出方式。

PS:题意就是求树的最长直径。题解:假如你的树上最长的路径的左右端点是。a,b。那么你从任意一点u出发搜到的最远的点一定是a、b中的一点,然后在从这个最远点开始搜,就可以搜到直径的另一个端点,所以要用两遍bfs或DFS。

BFS AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e6+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int head[maxn],cnt=1,n,dist[maxn],ans;
bool vis[maxn];
struct node
{
    int to,next;
}mp[maxn<<1];
void add(int u,int v)
{
    mp[++cnt].to=v;
    mp[cnt].next=head[u];
    head[u]=cnt;
}
void bfs(int x)
{
    queue<int>q;
    me(vis,0);dist[x]=1;
    q.push(x);
    while(!q.empty())
    {
        int temp=q.front();
        q.pop();
        for(int i=head[temp];i!=-1;i=mp[i].next)
            if(!vis[mp[i].to])
            {
                dist[mp[i].to]=dist[temp]+1;
                vis[mp[i].to]=1;
                q.push(mp[i].to);
                ans=max(ans,dist[mp[i].to]);
            }
    }
}
int main()
{
    cin>>n;
    me(head,-1),me(dist,0);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }

    ans=0;
    bfs(1);
    int pos=1;
    for(int i=1;i<=n;i++)
        if(dist[i]>dist[pos])
            pos=i;
    bfs(pos);
    cout<<ans<<endl;
    return 0;
}

 DFS AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e6+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int head[maxn],cnt=1,dist[maxn];
bool vis[maxn];
struct node
{
    int to,next;
}mp[maxn<<1];
void add(int u,int v)
{
    mp[++cnt].to=v;
    mp[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int x)
{
    vis[x]=1;
    for(int i=head[x];i!=-1;i=mp[i].next)
    {
        if(!vis[mp[i].to])
        {
             dist[mp[i].to]=dist[x]+1;
            dfs(mp[i].to);
        }

    }
}
int main()
{
    int n;cin>>n;
    me(head,-1),me(dist,0);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    me(vis,0);
    dfs(1);int pos=1;
    for(int i=1;i<=n;i++)
        if(dist[i]>dist[pos])
            pos=i;
    me(vis,0);
    dist[pos]=1;
    dfs(pos);
    int ans=0;
    for(int i=1;i<=n;i++)
        if(ans<dist[i])
            ans=dist[i];
    cout<<ans<<endl;
    return 0;
}

F-发电

链接:https://www.nowcoder.com/acm/contest/136/F
来源:牛客网
 

题目描述

    HA实验是一个生产、提炼“神力水晶”的秘密军事基地,神力水晶可以让机器的工作效率成倍提升。
    HA实验基地有n台发电机,标号为1-n,每台发电机的发电效率为1。
    为了满足基地的用电需求,HtBest会在某台发电机上镶嵌一个等级为i的神力水晶,该发电机的发电效率是镶嵌神力水晶之前的i倍,一个发电机可以同时镶嵌多个神力水晶。
    但是神力水晶有时还有别的用处,HtBest会拆掉某台发电机之前镶嵌上的一个神力水晶(设等级为i),发电机效率降为拆掉神力水晶前的1/i。
    HtBest有时想知道第l到r台发电机的总发电效率为多少。

输入描述:

第一行有2个正整数n,m,分别表示发电机数量和操作数。
接下来m行,每行有3个正整数,x, y, z。
x=1时,HtBest镶嵌为第y台发电机镶嵌了一个等级为z的神力水晶,
x=2时,HtBest为第y台发电机拆掉了一个等级为z的神力水晶,
x=3时,HtBest想知道[y,z]的发电机效率的乘积。

输出描述:

对于每个x=3的操作,输出一行,表示[y,z]的发电机的效率的乘积。
由于输出过大,你需要对输出结果模1000000007(1e9+7)。

示例1

输入

复制

4 4
1 2 3
3 1 4
2 2 3
3 1 4

输出

复制

3
1

说明

操作1之后,每台发电机效率:1 3 1 1
操作3之后,每台发电机效率:1 1 1 1

示例2

输入

复制

4 4
1 2 2
1 2 3
1 3 4
3 1 4

输出

复制

24

说明

操作1之后,每台发电机效率:1 2 1 1
操作2之后,每台发电机效率:1 6 1 1
操作3之后,每台发电机效率:1 6 4 1

备注:

对于100%的测试数据:
1 ≤ n, m ≤ 1000000
1 ≤ 神力水晶等级 ≤ 100000
数据量较大,注意使用更快的输入输出方式。

PS:裸的线段树,但是要注意,当x等于2的时候不能直接除,要用费马小定理求逆元,就因为这个错了两次,悲伤。

AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e6+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
ll num[maxn<<2];
void updata(int rt)
{
    num[rt]=(num[rt<<1]*num[rt<<1|1])%mod;
}
ll quick_pow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        num[rt]=1;
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    updata(rt);
}
void pushdata(int c,int flog,int x,int l,int r,int rt)
{
    if(l==r)
    {
        if(flog)
            num[rt]=(num[rt]*x)%mod;
        else
            num[rt]=num[rt]*quick_pow(x,mod-2)%mod;
        return ;
    }
    int m=(l+r)>>1;
    if(c<=m)
        pushdata(c,flog,x,l,m,rt<<1);
    else
        pushdata(c,flog,x,m+1,r,rt<<1|1);
    updata(rt);
}
int getma(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
        return num[rt];
    int m=(l+r)>>1;
    ll a=1,b=1;
    if(L<=m)
        a=getma(L,R,l,m,rt<<1);
    if(R>m)
        b=getma(L,R,m+1,r,rt<<1|1);
    return (a%mod*b%mod)%mod;
}
int main()
{
    int n,m;
    cin>>n>>m;
    build(1,n,1);
    while(m--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(a==1)
            pushdata(b,1,c,1,n,1);
        else if(a==2)
            pushdata(b,0,c,1,n,1);
        else
            printf("%d\n",getma(b,c,1,n,1));
    }
    return 0;
}

G 指纹锁(STL)

链接:https://www.nowcoder.com/acm/contest/136/G
来源:牛客网
 

题目描述

    HA实验有一套非常严密的安全保障体系,在HA实验基地的大门,有一个指纹锁。

    该指纹锁的加密算法会把一个指纹转化为一个不超过1e7的数字,两个指纹数值之差越小,就说明两个指纹越相似,当两个指纹的数值差≤k时,这两个指纹的持有者会被系统判定为同一个人。
    现在有3种操作,共m个,
操作1:add x,表示为指纹锁录入一个指纹,该指纹对应的数字为x,如果系统内有一个与x相差≤k的指纹,则系统会忽略这次添加操作
操作2:del x,表示删除指纹锁中的指纹x,若指纹锁中多个与x相差≤k的指纹,则全部删除,若指纹锁中没有指纹x,则可以忽略该操作,
操作3:query x,表示有一个持有指纹x的人试图打开指纹锁,你需要设计一个判断程序,返回该人是否可以打开指纹锁(只要x与存入的任何一个指纹相差≤k即可打开锁)。
    初始状态,指纹锁中没有任何指纹。
 

输入描述:

第一行有2个正整数m,k。
接下来m行,每行描述一种操作:add x,del x或query x。

输出描述:

对于每个query操作,输出一行,包含一个单词“Yes”或“No”,表示该人是否可以打开指纹锁。

示例1

输入

复制

4 3
add 1
add 10
query 5
query 4

输出

复制

No
Yes

示例2

输入

复制

4 3
add 1
query 4
del 1
query 4

输出

复制

Yes
No

示例3

输入

复制

6 3
add 10
query 10
add 5 
query 5
del 7		//系统将指纹10和指纹5全部删除
query 8

输出

复制

Yes
Yes
No

备注:

对于100%的测试数据:
1 ≤ k,m ≤ 1000000
数据量较大,注意使用更快的输入输出方式。

PS:主要考set的用法

AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e2+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int main()
{
    int m,k;
    scanf("%d%d",&m,&k);
    set<int>q;
    q.insert(inf);///避免set里面没有数的时候迭代器返回末尾位置
    while(m--)
    {
        int x;char s[10];
        scanf("%s %d",s,&x);
        set<int>::iterator it=q.lower_bound(x-k);
        if(s[0]=='a'&&(*it)>x+k)///如果返回的位置的值大于x+k说没有abs(*it-x)<=k
            q.insert(x);
        else if(s[0]=='d')
        {
             while(*it<=x+k)
            {
                q.erase(it);
                it=q.lower_bound(x-k);
            }
        }
        else if(s[0]=='q')
        {
            if(*it>x+k)///如果返回的位置的值大于x+k说没有abs(*it-x)<=k
                printf("No\n");
            else
                printf("Yes\n");
        }
    }
    return 0;
}

H 挖沟(最小生成树)

链接:https://www.nowcoder.com/acm/contest/136/H
来源:牛客网
 

题目描述


    胡队长带领HA实验的战士们玩真人CS,真人CS的地图由一些据点组成,现在胡队长已经占领了n个据点,为了方便,将他们编号为1-n,为了隐蔽,胡队长命令战士们在每个据点出挖一个坑,让战士们躲在坑里。由于需要在任意两个点之间传递信息,两个坑之间必须挖出至少一条通路,而挖沟是一件很麻烦的差事,所以胡队长希望挖出数量尽可能少的沟,使得任意两个据点之间有至少一条通路,顺便,尽可能的∑d[i][j]使最小(其中d[i][j]为据点i到j的距离)。

输入描述:

第一行有2个正整数n,m,m表示可供挖的沟数。
接下来m行,每行3个数a,b,v,每行描述一条可供挖的沟,该沟可以使a与b连通,长度为v。

输出描述:

输出一行,一个正整数,表示要使得任意两个据点之间有一条通路,至少需要挖长的沟。(数据保证有解)

示例1

输入

复制

2 2
1 2 1
1 2 3

输出

复制

1

示例2

输入

复制

3 3
1 2 3
2 3 4
1 3 5

输出

复制

7

备注:

对于100%的测试数据:
1 ≤ n ≤ 100000
1 ≤ m ≤ 500000
1 ≤ v ≤ 10000

AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=5e5+10;
const int mod=1e9+7;
const int inf=1e8+10;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int n,m,root[maxn];
struct node
{
    int x,y,len;
    bool friend operator<(node a,node b)
    {
        return a.len<b.len;
    }
}a[maxn];
void inct()
{
    for(int i=1;i<=n;i++)
        root[i]=i;
}
int find(int x)
{
    if(x==root[x])
        return x;
    return root[x]=find(root[x]);
}
void unite(int x,int y)
{
    int x1=find(x);
    int y1=find(y);
    if(x1!=y1)
        root[x1]=y1;
}
int kruskal()
{
    int res=0;
    for(int i=0;i<m;i++)
    {
        if(find(a[i].x)!=find(a[i].y))
        {
            unite(a[i].x,a[i].y);
            res+=a[i].len;
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    inct();
    for(int i=0;i<m;i++)
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].len);
    sort(a,a+m);
    cout<<kruskal()<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41292370/article/details/81942589