[bzoj4985]评分
二分答案,然后发现这相当于是一棵树,dp check就行了
- 代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int hed[N],to[N],nxt[N],cnt;
void adde(int u,int v) {
++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;
}
int n,m,q;
int tot,cur=0;
void init(int n) {
tot=n,cur=1;
for(int i=1; i<=n/2; ++i) {
++tot;
adde(tot,cur),adde(tot,cur+1),adde(tot,cur+2);
cur+=3;
}
}
int pl[N],sum[N],s[N];
long long cnt1;
long long dp[N][2];
bool vis[N];
void dfs(int u) {
if(u<=n)return;
int s=0,a[4];
for(int i=hed[u]; i; i=nxt[i]) {
int v=to[i];
dfs(v);
a[++s]=v;
}
dp[u][0]=min(dp[a[1]][0],dp[a[1]][1])+min(dp[a[2]][0],dp[a[2]][1])+min(dp[a[3]][0],dp[a[3]][1]);
dp[u][1]=min( dp[a[1]][1]+dp[a[2]][1]+dp[a[3]][1],
min( dp[a[1]][1]+dp[a[2]][1]+dp[a[3]][0],
min( dp[a[1]][1]+dp[a[2]][0]+dp[a[3]][1],
dp[a[1]][0]+dp[a[2]][1]+dp[a[3]][1] ) ) );
}
bool chk(int Sum) {
cnt1=0;
for(int i=1; i<=n; i++) {
if(sum[i]>=Sum)cnt1++;
if(pl[i]) {
dp[pl[i]][0]=sum[i]>=Sum?1000001:0;
dp[pl[i]][1]=sum[i]>=Sum?1:1000001;
}
}
for(int i=1; i<=n; i++)if(!vis[i]) {
dp[i][0]=0,dp[i][1]=1;
}
dfs(tot);
return dp[tot][1]<=cnt1;
}
int main()
{
scanf("%d%d",&n,&q);
m=n-q;
init(n);
for(int i=1; i<=n; i++) {
scanf("%d",&sum[i]);s[i]=sum[i];
if(i<=q) {
scanf("%d",&pl[i]);
vis[pl[i]]=true;
}
}
sort(s+1,s+n+1);
int l=1,r=n;
while(l<r) {
int mid=(l+r+1)>>1;
if(chk(s[mid]))l=mid;
else r=mid-1;
}
printf("%d\n",s[l]);
}