luogu P1084 疫情控制
阿新 • • 發佈:2018-09-22
enable -- 節點和 using 時間排序 cmp printf fin tps
傳送門
首先,所有軍隊又要盡量往上走,這樣才能盡可能的封鎖更多的到葉子的路徑
而隨著時間的增加,能封鎖的路徑也就越來越多,所以可以二分最終的時間
然後對於每個時間,就讓能走到根的軍隊走到根,記錄到根上一個節點和剩余時間,然後按時間排序;不能走到的就在能走到的最上面的點打標記.然後遍歷樹一遍,把所有的兒子被打標記的點打標記;然後把根的沒打標記的兒子提出來,和之前到達根的軍隊一一匹配:把那些兒子按照到根的距離從大到小排序,對於每個兒子,考慮用退回上一個節點匹配,不行就用剩余時間足夠的匹配,都不行就用當前軍隊退回去匹配,然後考慮下一個軍隊
有點毒瘤似不似
註:保存到根的節點建議用\(multiset\) ,向下面代碼裏面寫的能過洛谷上的題,但是仍有問題懶得改了
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long long #define il inline #define re register #define inf 2099999999 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define db double #define eps (1e-5) using namespace std; const int N=50000+10; il LL rd() { re LL x=0,w=1;re char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int to[N<<1],nt[N<<1],hd[N],tot=1; LL w[N<<1]; il void add(int x,int y,LL z) { ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot; ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot; } struct nnn { LL x;int la; bool operator < (const nnn &a) const{return x>a.x;} }st[N<<1]; int n,m,nn,a[N],fa[N][17],tt,tp,cn[N]; LL s[N][17],di[N],l,r,ans,so[N]; bool v[N]; il bool cmp(int a,int b){return di[a]>di[b];} void dfs(int x) { r=max(r,di[x]); for(int j=1;j<=nn;j++) fa[x][j]=fa[fa[x][j-1]][j-1],s[x][j]=(fa[x][j]>0)?(s[x][j-1]+s[fa[x][j-1]][j-1]):(1ll<<50); for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(y==fa[x][0]) continue; fa[y][0]=x,s[y][0]=w[i],di[y]=di[x]+w[i]; dfs(y); } } void dd(int x) { if(v[x]) return; v[x]=true; int cnt=0; for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(y==fa[x][0]) continue; dd(y); v[x]&=v[y]; ++cnt; } if(!cnt) v[x]=false; } il bool check(LL ti) { memset(v,0,sizeof(v)); memset(cn,0,sizeof(cn)); tt=tp=0; for(int i=1;i<=m;i++) { if(di[a[i]]<ti) { int nw=a[i]; for(int j=nn;j>=0;j--) if(fa[nw][j]>1) nw=fa[nw][j]; st[++tt]=(nnn){ti-di[a[i]],nw},++cn[nw]; continue; } int nw=a[i];LL ss=0; for(int j=nn;j>=0;j--) if(ss+s[nw][j]<=ti&&fa[nw][j]>1) ss+=s[nw][j],nw=fa[nw][j]; if(nw>1) v[nw]=true; } sort(st+1,st+tt+1); dd(1); for(int i=hd[1];i;i=nt[i]) if(!v[to[i]]) so[++tp]=to[i]; sort(so+1,so+tp+1,cmp); int j=1; for(int i=1;i<=tt&&j<=tp;i++) { if(cn[so[j]]>0) --cn[so[j]],--i,v[so[j]]=true; else if(st[i].x>=di[so[j]]&&cn[st[i].la]>0) --cn[st[i].la],v[so[j]]=true; else if(cn[st[i].la]>0) --cn[st[i].la],st[++tt]=(nnn){st[i].x,st[i].la},v[st[i].la]=true; while(j<=tp&&v[so[j]]==true) ++j; } return j>tp; } int main() { n=rd(),nn=log(n)/log(2)+1; for(int i=1;i<n;i++) { int x=rd(),y=rd(),z=rd(); add(x,y,z); } dfs(1); m=rd(); for(int i=1;i<=m;i++) a[i]=rd(); l=0,r<<=1ll,ans=1ll<<60; while(l<=r) { LL mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%lld\n",ans<(1ll<<60)?ans:-1); return 0; }
luogu P1084 疫情控制