n^2log动态规划
新生赛题
F. tree options
如果能想到弱化版操作为每个节点值都小于等于0,就很容易想到n方log的做法。
但是回到原题会发现单调性有变化,不能直接二分。由于奇数轮数和偶数轮数分别有自己的单调性,就可以对奇偶轮数分别二分然后枚举非整轮部分。dp算每个点还要多少次能变为合法点。
题解有复杂度优化待学。
代码在好几个地方写挂了
1.ans大小
2.对奇数偶数轮数二分的方法
3.不知道为什么函数传值比开数组快了1s。。
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define pii pair<int, int>
#define mkp make_pair
#define LL long long
#define ll long long
#define endl '\n'
const int N = 2e3 + 10, inf = 1e9;
LL n, rt, f[N], a[N], p, nw;
vector<int>E[N];
void dfs(int x, int fa) {
f[x] = a[x];
LL tmp = nw + (x <= p);
for (int i:E[x]){
if(i == fa) continue;
dfs(i, x);
f[x] += f[i];
}
f[x] = (f[x]-tmp > 0) ?(f[x] - tmp) : (f[x] - tmp & 1);
// if(p == 0)cout << f[x] << ' '<< x << 'x' << tmp << endl;
}
void solve()
{
cin >> n >> rt;
for(int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
E[u].push_back(v);
E[v].push_back(u);
}
if (n == 1) {
cout << a[1] << endl;
return;
}
LL ans = 1ll*inf*N;
for(int i = 0; i < n; i++)
{
p = i;
LL l = 0, r = inf, mid = (l+r)/2;
while(l < r) {
nw = mid*2+1;
dfs(rt, 0);
if(f[rt]) l = mid + 1;
else r = mid;
mid = (l + r) / 2;
}
ans = min(ans, (mid * 2 + 1) * n + i);
l = 0, r = inf, mid = (l + r) / 2;
while(l < r) {
nw = mid*2;
dfs(rt, 0);
if(f[rt]) l = mid + 1;
else r = mid;
mid = (l + r) / 2;
}
ans = min(ans, mid*2*n + i);
}
if(ans == 1ll*inf*N)cout<<-1<<endl;
else cout<<ans<<endl;
for (int i = 0;i <= n; i++)E[i].clear();
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
cin >> T;
while (T--)
solve();
}
/*
1
3 2
2 1 3
2 1
3 2
*/