生活随笔
收集整理的這篇文章主要介紹了
bzoj2525 1426
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題面二分最短時間,求出最小的需要引爆數
至于關鍵點的引爆狀態有關
f[i] 以i為根的子樹中已經引爆的點離i最近的距離
g[i] 以i為根的子樹中未引爆的點離i最遠的距離
回溯到每個節點時,優先考慮用另一個兒子中的點覆蓋其他兒子
if(f[i]+g[i]<=mid) g[i]=INF
if(g[i]==mid) 必須引爆x
using namespace std;
int n,
m;
int a[maxn];
int ans;
struct edge{
int to,
ne;
}b[maxn
*2];
int k=
0,head[maxn];
int f[maxn],g[maxn];
int limit;
int num=
0,op1=
0;
inline
int read()
{
int x=
0,f=
1;char ch=getchar();
while(ch<
'0'||ch>
'9'){
if(ch==
'-') f=-
1; ch=getchar(); }
while(ch>=
'0'&&ch<=
'9'){
x=
x*10+ch-
'0'; ch=getchar(); }
return x*f;
}void add(
int u,
int v)
{k++;b[k].to=v; b[k].
ne=head[u]; head[u]=k;
}
void dfs(
int x,
int pre)
{f[
x]=INF;
if(a[
x]) g[
x]=
0;
else g[
x]=-INF;
for(
int i=head[
x];i!=-
1;i=b[i].
ne)
if(b[i].to!=pre){dfs(b[i].to,
x);f[
x]=min(f[
x],f[b[i].to]+
1);g[
x]=max(g[
x],g[b[i].to]+
1);}
if(g[
x]+f[
x]<=limit) g[
x]=-INF;
if(g[
x]==limit){f[
x]=
0,g[
x]=-INF,num++;}
}bool check(
int x)
{
if(!
x)
return op1<=
m;limit=
x; num=
0;dfs(
1,
0);
//printf(
"%d %d %d %d\n",
x,f[
1],g[
1],num);
if(g[
1]+f[
1]>limit) num++;
return num<=
m;
}void getans()
{
int l=
0,r=n,mid;ans=n;
while(l<=r){mid=(l+r)>>
1;
if(check(mid)) ans=mid,r=mid-
1;
else l=mid+
1;}
}
int main()
{
//freopen(
"in.txt",
"r",stdin);memset(head,-
1,sizeof(head));n=
read();
m=
read();
for(
int i=
1;i<=n;i++){a[i]=
read();
if(a[i]) op1++;}
int x,
y;
for(
int i=
1;i<n;i++){
x=
read();
y=
read();add(
x,
y); add(
y,
x);}getans();
printf(
"%d\n",ans);
//while(
1);
return 0;
}
題面
考慮逆推
f[i] 已經買了i張郵票,距離n張郵票還需要的購買次數
f[i]=in?f[i]+n?in?f[i+1]+1
f[i]=f[i+1]+nn?i
g[i]表示所需錢數
假設每張郵票需要一元,后面購買的郵票都會貴1元
g[i]=in?(g[i]+f[i])+n?in?(g[i+1]+f[i+1])+1
總結
以上是生活随笔為你收集整理的bzoj2525 1426的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。