http://codeforces.com/contest/1436

D. Bandit in a City

 

题意:给定一棵有根树,以1为根。每个点有一些人,这些人最终都走到叶子,要使得包含人最多的叶子上包含的人数最少。

这就是要求均分,且每个点只能向子孙分配。

树上的均分可以从下向上遍历,同时求均值,这样就能保证那些本来就很多,而又没法向其它点分配的点均值不会变小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(x) cout<<#x<<":\t"<<x
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int n;
vector<int>G[N];
ll a[N],sum[N],cnt[N];
ll ans;
void dfs(int u){
sum[u]=a[u];
if(G[u].empty()){
cnt[u]=1;
}
for(int v:G[u]){
dfs(v);
sum[u]+=sum[v];
cnt[u]+=cnt[v];
}
ans=max(ans,(sum[u]+cnt[u]-1)/cnt[u]);
}
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++){
int p;
scanf("%d",&p);
G[p].push_back(i);
}
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
dfs(1);
printf("%lld\n",ans);
return 0;
}

 

E. Complicated Computations

 

题意:给定一个 n 个元素的数列A,1ain1\le a_i\le n,把所有非空连续子数组的MEX值放入一个集合,求这个集合的MEX值。

线段树

易知最终MEX只会在1到 n+2,所以从小到大枚举,第一个满足没有出现在集合里的数就是答案。

也就是要确定是否有非空连续子数组的MEX值为 x。

遍历 A 数组,aia_i 前一次出现的位置为 lastilast_i,则 (lasti,i)(last_i,i) 这一段中不含有 aia_i,则只要这一段中包含 [1,ai1][1,a_{i-1}] 中的所有数,这段就以 aia_i 为MEX。

线段树维护每个数最后一次出现的位置,只要都大于 lastilast_i,则都出现了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <bits/stdc++.h>
#define debug(x) cout << #x << ":\t" << (x) << endl;
using namespace std;
#define ll long long
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
int n;
int a[N], c1;
#define mid ((l+r)>>1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int mn[N << 2];
void up(int rt) {
mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]);
}
int qry(int ql, int qr, int l, int r, int rt) {
if (ql <= l && qr >= r)return mn[rt];
int ans = INF;
if (ql <= mid)ans = min(ans, qry(ql, qr, lson));
if (qr > mid)ans = min(ans, qry(ql, qr, rson));
return ans;
}
void upd(int q, int x, int l, int r, int rt) {
if (l == r) {
mn[rt] = x;
return;
}
if (q <= mid)upd(q, x, lson);
else upd(q, x, rson);
up(rt);
}
int gg[N];
int last[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)scanf("%d", &a[i]), c1 += (a[i] == 1);
if (c1 == n) {
puts("1");
return 0;
}
gg[1] = 1;
for (int i = 1; i <= n; i++) {
if (a[i] != 1) {
int x = qry(1, a[i] - 1, 1, n, 1);
if (x > last[a[i]]) {
gg[a[i]] = 1;
}
}
last[a[i]] = i;
upd(a[i], i, 1, n, 1);
}
for (int i = 2; i <= n + 1; i++) {
if (qry(1, i - 1, 1, n, 1) > last[i])gg[i] = 1;
}
for (int i = 1; i <= n + 2; i++)if (!gg[i]) {
printf("%d\n", i);
return 0;
}
return 0;
}