AtCoder Beginner Contest 187题解(D~E)

AtCoder Beginner Contest 187

D - Choose Me

题意

  现给定\(n\)个城市,第\(i\)城市分别有\(a_i\)个人投票给\(A\),有\(b_i\)个人投票给\(B\),现在\(B\)可以选择到一些城市演讲,\(B\)所到达的城市中的所有人将会给他投票,其他城市的人,支持\(A\)投票的人将依旧给\(A\)投票,但是支持\(B\)的人将不会投票。现\(B\)想要得到的票数大于\(A\),最少需要到达的城市数量是多少。

题解

  一开始,\(B\)还没有前往任何城市,\(tot_B=0\)(因为没有人给\(B\)投票),而\(tot_A=\sum_{i=1}^{n}a[i]\)。每次\(B\)到访一个城市后,\(tot_B+=a[i]+b[i]\),而\(tot_A-=a[i]\),因此\(A\)和\(B\)之间票数的差距\(gap+=a[i]+a[i]+b[i]\)。

  因此我们可以记录下当访问每个城市时,可以减少的\(A\)与\(B\)之间的差距\(dif\),即\(a[i]+a[i]+b[i]\)。由于需要求得最少的访问城市数量,因此我们只需要对\(dif\)数组进行排序,每次加上最大值,直到他们之间的票数差距变成正数。

参考代码

点此展开
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int main()
{
    int n;
    cin >> n;

    LL gap=0;
    vector<LL> dif(n);
    for(LL i=0; i<n; i++)
    {
        LL a,b;
        cin>>a>>b;
        gap-=a;
        dif[i]=a+a+b;
    }

    sort(dif.begin(),dif.end());
    LL ans=0;
    while(gap<=0){
        ans++;
        gap+=dif.back();
        dif.pop_back();
    }

    cout << ans << endl;

    return 0;
}

E - Through Path

题意

  现有一颗树,有\(n\)个结点和\(n-1\)条边,每个结点初始值为\(0\),现有\(q\)次询问,当\(t=1\)时,每个能够从\(a_{e_i}\)不经过\(b_{e_i}\)访问到的结点的值增加\(x\)。当\(t=2\)时,每个能够从\(b_{e_i}\)不经过\(a_{e_i}\)访问到的结点的值增加\(x\)。经过\(q\)次访问后,输出最终每个结点的值。

题解

  由于每次题目给定的结点的连接方式,每次询问的\(a_{e_i}\)与\(b_{e_i}\)必定是两个相邻的结点。因此每次都可以将树分成两个部分。对于每次询问需要增加的所有结点,我们都可以统一地认为是从以某个结点为根的树,将\(x\)增加到其所有的子孙。
  利用差分的思想,我们只需要在特定结点增加\(x\)和减去\(x\),再求前缀和就可以得到所有结点的最终值。由于每次询问我们只需要\(O(1)\)的时间修改,在最后输出的时候求取总和即可。因此本算法的时间复杂度为\(O(N+W)\)。

参考代码

点此展开
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<LL,LL> PLL;

int main()
{
    int n,q;
    cin>>n;

    vector<PLL> edge(n-1);
    vector<LL> node[n];
    vector<LL> s(n,0);
    for(int i=0;i<n-1;i++){
        LL a,b;
        cin>>a>>b;
        a--,b--;
        node[a].push_back(b);
        node[b].push_back(a);
        edge[i]={a,b};
    }

    vector<LL> dep(n,-1);
    queue<LL> que;
    dep[0]=0;
    que.push(0);
    while(que.size()){
        auto v=que.front();
        que.pop();
        for(int i=0;i<(int)node[v].size();i++){
            int j=node[v][i];
            if(dep[j]==-1){
                dep[j]=dep[v]+1;
                que.push(j);
            }
        }
    }

    cin>>q;
    while(q--){
        LL t,e,x;
        cin>>t>>e>>x;
        LL a=edge[e-1].first;
        LL b=edge[e-1].second;
        
        if(dep[a]>dep[b]){//主要转换
            swap(a,b);
            t^=3;
        }

        if(t==1){
            s[0]+=x;
            s[b]-=x;
        }else s[b]+=x;
    }
    que.push(0);
    while(que.size()){
        int v=que.front();
        que.pop();
        for(int i=0;i<(int)node[v].size();i++){
            int j=node[v][i];
            if(dep[v]<dep[j]){//只有是其子孙才会继续累计
                s[j]+=s[v];
                que.push(j);
            }
        }
    }
    
    for(LL i=0;i<n;i++) cout<<s[i]<<endl;
    return 0;
}
上一篇:leetcode-187周赛-5400-旅行终点站


下一篇:如何用JavaScript实现轮播图的滚动效果