Comet OJ - Contest #5 D 迫真小游戏 (堆+set)

迫真小游戏
已经提交 已经通过 时间限制:2000ms 内存限制:256MB

73.98%
提交人数:196

通过人数:145

题目描述

H君喜欢在阳台晒太阳,闲暇之余他会玩一些塔防小游戏。

H君玩的小游戏可以抽象成一棵 nn 个节点的有根树,树以 11 为根,每个点的深度定义为其到根的简单路径上的点数(根的深度为 11)。

H君有 nn 个干员,H君会按照某种顺序把她们部署到树的每一个节点上,使得每个节点上恰好有一个干员。由于游戏的机制,他们对每个节点 ii 都给出了个限制参数 a_ia
i
?
,要求H君在第 ii 个节点部署干员之前,所有深度 > a_i>a
i
?
的节点上不能有干员。同时游戏为了让玩家过关,保证了 a_ia
i
?
大于等于点 ii 的深度。

H君将每一次部署干员的节点按顺序写在纸上,形成了一个 1 \dots n1…n 的排列,H君为了获得更多的奖励,想要最小化这个排列的字典序。

我们认为排列 c_1,c_2..c_nc
1
?
,c
2
?
..c
n
?
的字典序比排列 d_1,d_2..d_nd
1
?
,d
2
?
..d
n
?
的字典序小,当且仅当 c, dc,d 不完全相同且存在一个下标 ii,满足 c_i < d_ic
i
?
<d
i
?
且对于所有 1 \le j < i1≤j<i 的 jj 都有 c_j = d_jc
j
?
=d
j
?

输入描述

第一行一个数 nn 。

接下来 n - 1n?1 行,每行两个数 x, yx,y 表示树上的一条边 。

最后一行 nn 个数,表示 a_ia
i
?

数据范围:

1\le n \le 5 \times 10^5, 1 \le a_i \le n1≤n≤5×10
5
,1≤a
i
?
≤n。

输出描述

第一行 nn 个数,表示字典序最小的排列。

样例输入 1

5
1 5
5 3
1 4
4 2
1 3 3 3 2
样例输出 1

1 4 5 2 3
样例输入 2

10
1 7
7 8
7 2
8 9
7 6
2 4
9 5
8 10
6 3
5 3 4 4 5 3 5 3 5 4
样例输出 2

1 2 6 7 8 3 4 9 10 5

题意:

思路:
首先dfs把整颗树跑一遍,得出每一个节点在第几层的信息,然后我们从1到n层扫一遍,对于每一层,我们把这一层上的所以节点操作,如果这个节点的a[i] 值是等于i的,那么这个节点在这一次操作中必须要部署,所以加入到一个大根堆中,否则加入到一个set中,同时用一个vector维护set中每一个a[i] 值加入了那些节点, 然后我们再从vector中查找是否有当前第i层的节点被介入到了set中,如果有就把它取出加入大根堆 ,然后把set的第一个元素(id最小的)与大根堆的堆顶(id最大的元素)比较,如果小于,就把它从set中取出,加入到堆中,一直这样操作,直到大于堆顶或者set为空,这样就可以使其字典序最小。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=6e5;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
std::vector<int> son[maxn];
int n;
int a[maxn];
int depth[maxn];
void dfs(int x,int pre)
{
    depth[x]=depth[pre]+1;
    for(auto y:son[x])
    {
        if(y!=pre)
        {
            dfs(y,x);
        }
    }
}
bool vis[maxn];
std::vector<int> ans;
struct node
{
    int ai;
    int id;
    node(){}
    node(int ii,int aai)
    {
        id=ii;
        ai=aai;
    }
    friend bool operator < (node x,node y)
    {
        //set套结构体要重载<运算符
        return x.id < y.id;
    }
};
struct cmp
{
    bool operator ()(const node p1,const node p2)
    {
        return p1.id>p2.id;// 以first为比较对象的小根堆
    }
};
struct cmp2
{
    bool operator ()(const node p1,const node p2)
    {
        return p1.id<p2.id;// 以first为比较对象的小根堆
    }
};
std::vector<node>  ceng[maxn];
set<node> xgd;
priority_queue<node,vector<node>,cmp2 > dgd;
std::vector<int> jia[maxn];
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    gbtb;
    cin>>n;
    int u,v;
    repd(i,2,n)
    {
        cin>>u>>v;
        son[v].pb(u);
        son[u].pb(v);
    }
    repd(i,1,n)
    {
        cin>>a[i];
        vis[a[i]]=1;
    }
    depth[0]=0;
    dfs(1,0);
    repd(i,1,n)
    {
        ceng[depth[i]].pb(node(i,a[i]));
    }
    repd(i,1,n)
    {
        for(auto x:ceng[i])
        {
            if(x.ai==i)
            {
                dgd.push(x);
            }else
            {
                xgd.insert(x);
                jia[x.ai].pb(x.id);
            }
        }
        for(auto x:jia[i])
        {
            if(xgd.count(node(x,a[i]))==1)
            {
                xgd.erase(node(x,a[x]));
                dgd.push(node(x,a[x]));
            }
        }
        while((xgd.size()>0)&&(!dgd.empty())&&((*xgd.begin()).id<dgd.top().id))
        {
            dgd.push(*xgd.begin());
            xgd.erase(xgd.begin());
        }
        std::vector<int> v;
        v.clear();
        while(!dgd.empty())
        {
            v.push_back(dgd.top().id);
            dgd.pop();
        }
        reverse(ALL(v));
        for(auto y:v)
            ans.push_back(y);
    }

    while(!xgd.empty())
    {
        ans.pb((*xgd.begin()).id);
        xgd.erase(xgd.begin());
    }
    for(int i=0;i<ans.size();i++)
    {
        if(i!=0)
        {
            cout<<" "<<ans[i];
        }else{
            cout<<ans[i];
        }
    }
    cout<<endl;

    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}

原文地址:https://www.cnblogs.com/qieqiemin/p/11031173.html

时间: 2024-11-01 15:30:28

Comet OJ - Contest #5 D 迫真小游戏 (堆+set)的相关文章

Comet OJ - Contest #5

Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下,最大的满足条件的\(x\)不会太大 因为当\(x\)越来越大时\(f(x)\)的增长速度比\(x\)的增长速度慢得多 其实可以证明,最大的满足的\(x\)不会超过\(100\) 因为没有任何一个三位数的各位之和大于等于\(50\) 所以我们就直接预处理\(1-99\)所有的合法的 暴力枚举即可 其实

符文能量(Comet OJ - Contest #8)

给Comet OJ打个小广告,挺好用的,比较简洁,给人感觉很好用 Contest #8是我打的第一场本oj比赛,很遗憾A了前两道傻逼题就没思路了,然后就不打算打了....... https://www.cometoj.com/contest/58/problem/C?problem_id=2760 怎么做啊完全不会啊我那么菜,虽然看到是dp但嫌太麻烦就放弃了: 靠后仔细想了想原来这道题很简单: 结构体node e[];储存ai,bi值(当然你用数组我也不拦着),因为合并的方式很特殊,可以不管合并

Comet OJ - Contest #10 B

Comet OJ - Contest #10 B 沉鱼落雁 思维题 题意 : 每个数字最多重复出现三次,有n给数字,让你尽可能的使得相同数字之间的最小距离尽可能大 思路 :分三种情况套路 设 a b c 分别代表出现 一次, 两次, 三次 数字的个数 所有元素至多出现一次,答案为 n,题目规定 所有元素至多出现两次, 例如 1 1 2,可以排列成 1 2 1,所以,答案为 1 例如 1 1 2 2 3,可以排列成 1 2 3 1 2,所有 答案为 2 思考后得出,应该尽可能的把 b 个出现两次的

Comet OJ - Contest #15题解

A 双十一特惠 (简单版) n  <=  1e19,   1e9 > 1(8) https://www.cometoj.com/contest/79/problem/A?problem_id=4198 #include<bits/stdc++.h> using namespace std; int main(){ int t; cin >> t; while(t--) { int cnt1 = 0; int n;cin >> n; int pr[] = {1

Comet OJ - Contest #0

A:化成x-√n=y+z-√4yz的形式,则显然n是完全平方数时有无数组解,否则要求n=4yz,暴力枚举n的因数即可.注意判断根号下是否不小于0. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long

Comet OJ - Contest #1

A:随便怎么暴力. #include<bits/stdc++.h> using namespace std; #define ll long long #define N 25 char getc(){char c=getchar();while (c!='.'&&c!='#') c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char

Comet OJ Contest #3

A:签到. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 510 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}

[Comet OJ - Contest #4 D][39D 1584]求和_&quot;数位dp&quot;

求和 题目大意: 数据范围: 题解: 脑筋急转弯可还行..... 我们发现只需要最后枚举个位/xk/xk 因为前面的贡献都是确定的了. 故此我们最后暴力统计一下就好咯. 不知道为啥我组合数一直过不去,暴力求过了呜呜. 代码: #include <bits/stdc++.h> using namespace std; typedef long long ll; char *p1, *p2, buf[100000]; #define nc() (p1 == p2 && (p2 =

[Comet OJ - Contest #6 C][48C 2279]一道树题_树

一道树题 题目大意: 给定一棵树,边的编号为读入顺序.现在规定,区间$[L, R]$的贡献$S(L,R)$为把编号在该区间里的边都连上后,当前形成的森林中点数大于等于$2$的联通块个数. 求$\sum\limits_{i = 1} ^ {N - 1}\sum\limits_{j = i} ^ {N - 1}S(i,j)$. 数据范围:$2\le N\le 10^5$. 题解: 水题. 我们发现,一棵树上假设联通了$k$条边,那么联通块个数就是$N-k$个.所以我们可以求出,所有区间下的所有联通块