Luogu P1084 疫情控制
再水篇博客
2019.8.28
騙-1分未遂
打了個二分不會check 勸退
2019.9.29(一個月了啊…)
怎麼說都要打下來
這個題解好哇
註釋了一些在代碼裏
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll ans=-1,sumc=0,l,r;
ll dis[500100][30],path[500100],dep[500100];
int first[500100];
int f[500100][30];
struct nod1{int y,next;ll c;}a[1000010];
struct nod2{int x,old;ll left;}act[500100],wait[500100];
int n,m,army[500100],need=0,can=0,len=0;
int used[500100],v[500100],stay[500100];
void ins(int x,int y,ll c)
{
len++;
a[len].y=y;
a[len].c=c;
a[len].next=first[x];
first[x]=len;
}
void pre(int x,int ff)
{
for(int i=1;i<=25;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1];
//這個!!距離的倍增式不要忘加dis[x][i-1] !!!!!!
}
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==ff)continue;
f[y][0]=x;
dis[y][0]=a[i].c;
path[y]=path[x]+a[i].c;
dep[y]=dep[x]+1;
pre(y,x);
}
}
void move(ll nowc)
{
for(int i=1;i<=m;i++)
{
int x=army[i];
ll went=0;
for(int j=25;j>=0;j--)
{
if(dep[f[x][j]]>1&&(went+dis[x][j]<=nowc))
{
went+=dis[x][j];
x=f[x][j];
}
}
if(f[x][0]==1&&(went+path[x])<=nowc)
{
can++;
act[can].x=x;
act[can].old=can;//因爲要排序,然而標記(在子樹x中,可以到達根節點,
//且到根節點後剩餘路程最小的軍隊)是用原編號
//所以記錄一下原編號
act[can].left=nowc-(went+path[x]);
if(act[can].left<act[stay[x]].left||stay[x]==0)
{
stay[x]=can;
}
}
else
{
v[x]=1;
}
}
}
void find(int x,int ff)
{
int sum1=0,sum2=0;
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==ff)continue;
sum1++;find(y,x);
if(v[y]==1)sum2++;
}
if(sum1!=0&&sum1==sum2)v[x]=1;
if(x==1)
{
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==ff)continue;
if(v[y]==0)
{
need++;
wait[need].left=path[y];
wait[need].x=y;
}
}
}
}
int cmp(nod2 x,nod2 y)
{
return x.left>y.left;
}
int check(ll nowc)
{
for(int i=1;i<=n;i++)
stay[i]=0,v[i]=0;
can=0;
move(nowc);//3.先跳軍隊
for(int i=1;i<=can;i++)
used[i]=0;
need=0;
find(1,0);//4.檢查子樹
if(can<need)return 0;
sort(wait+1,wait+1+need,cmp);
sort(act+1,act+1+can,cmp);
int now=1;
for(int i=1;i<=need;i++)//5.分配他們
{
int x=wait[i].x;
if(used[stay[x]]==0&&stay[x]!=0)
//這裏!!要判當前要填的子樹 有沒有stay(可以到達根節點,且到根節點後剩餘路程最小的軍隊)
{
used[stay[x]]=1;
if(stay[x]==act[now].old)now++;
continue;
}
if(act[now].left<wait[i].left)return 0;
used[act[now].old]=1;now++;
}
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;ll c;
scanf("%d %d %lld",&x,&y,&c);
ins(x,y,c);ins(y,x,c);
sumc+=c;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
scanf("%d",&army[i]);
dep[1]=1;
path[1]=0;
pre(1,0);//1.先預處理出倍增數組
ll l=0,r=sumc;
while(l<=r)//2.二分
{
ll mid=(l+r)/2;
if(check(mid))
{
ans=mid;
r=mid-1;
}else l=mid+1;
}
printf("%lld",ans);
}
剛剛溜去看合唱比賽了
我們班天耀中華唱的好好!
雖然我不上臺在臺下有點寂寞
但真的好激動啊 真好
我知道他們練得很刻苦
我也要努力啊!