Luogu 1084 [Increased 2012] Epidemic Control (Dichotomy + Greed + Double)

Keywords: REST

This is a really awesome question... One day...
Despite the fact that I got a dichotomy in D2T2, D2T3 is also a dichotomy!! Surprise! No surprise! What? Did you say I was greedy and doubled? Is that more surprising? What a surprise!
Obviously, the longer the minimum transfer time is, the more likely it is to meet the conditions. So we dichotomize the answer and turn the original question into a question of determining feasibility with a given mobilization time. Obviously, the more an army follows the borders it can cover. We can divide the former army into two categories according to the time of mobilization: (fast implementation by multiplying trees)
1. If you can't get to the root, go to the root as far as possible. Obviously, this is the best way.
2. If you can follow, you will have to wait at the root and figure out the remaining time.
For those who fail to follow, they are already optimal, and dfs records over and over which points have been covered (one point is covered, if and only if all his sons are covered). Now we only care about the sons of Root. We need to mobilize the troops that still have time to cover the sons who are not covered. How to distribute the army? We had to distribute greedily. Sort the troops to the roots from small to large in the remaining time as q arrays, and the sons of the roots that need to be covered as b arrays from small to large in the distance to the roots. We greedily let the rest of the time small to cover the need for time small. But there is one more detail. If an army comes from the son of a and reaches the root, but the rest of the time is not enough to go back to a, let's let him stay in a directly. It's certainly better. It can be proved that:
If the army goes to point x elsewhere, and then the Y army fills in point a, the known D (a) > D (x) obviously lets y go to X. This army is better stationed in point A.

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define pa pair<ll,int>
#define N 50010
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;
}
int n,m,h[N],num=0,a[N],fa[N][18],son[N],Log[N],bel[N];
ll d[N][18],l=0,r=500000,ans=0;
bool mark[N],used[N];
struct edge{
    int to,next,val;
}data[N<<1];
void dfs(int x,int tp){
    bel[x]=tp;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;if(y==fa[x][0]) continue;
        fa[y][0]=x;d[y][0]=data[i].val;dfs(y,tp);
    }
}
void dfs1(int x){
    bool flag=1,fson=0;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;if(y==fa[x][0]) continue;fson=1;
        dfs1(y);if(!mark[y]) flag=0;
    }
    if(fson&&flag) mark[x]=1;
}
bool jud(ll tot){
    memset(mark,0,sizeof(mark));memset(used,0,sizeof(used));
    vector<pa>q;vector<pa>b;
    for(int i=1;i<=m;++i){
        int x=a[i];ll dx=0;
        for(int j=Log[n];j>=0;--j)
            if(fa[x][j]&&dx+d[x][j]<=tot)
                dx+=d[x][j],x=fa[x][j];
        if(x!=1) mark[x]=1;
        else q.push_back(make_pair(tot-dx,bel[a[i]]));
    }dfs1(1);if(mark[1]) return 1;
    for(int i=1;i<=son[0];++i){
        int y=son[i];if(mark[y]) continue;
        b.push_back(make_pair(d[y][0],y));
    }sort(b.begin(),b.end());sort(q.begin(),q.end());
    for(int i=0;i<q.size();++i){//If the rest of the time is not enough to come back, don't go to the root. 
        int x=q[i].second;
        if(!mark[x]&&q[i].first<d[x][0]) mark[x]=1,used[i]=1;
    }int pq=0,pb=0;
    while(pq<q.size()&&pb<b.size()){//Greedy distribution of troops 
        if(used[pq]){pq++;continue;}
        if(mark[b[pb].second]){pb++;continue;}
        if(q[pq].first<b[pb].first) pq++;
        else pq++,pb++;
    }while(pb<b.size()&&mark[b[pb].second]) pb++;
    if(pb==b.size()) return 1;
    else return 0;
}
int main(){
//  freopen("blockade4.in","r",stdin);
    n=read();Log[0]=-1;for(int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
    for(int i=1;i<n;++i){
        int x=read(),y=read(),val=read();
        data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
        data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=val;
        if(x!=1&&y!=1) continue;
        son[++son[0]]= x==1?y:x;
        fa[son[son[0]]][0]=1;d[son[son[0]]][0]=val;
    }m=read();if(son[0]>m){puts("-1");return 0;}
    for(int i=1;i<=son[0];++i) dfs(son[i],son[i]);
    for(int i=1;i<=Log[n];++i)
        for(int j=1;j<=n;++j)
            fa[j][i]=fa[fa[j][i-1]][i-1],d[j][i]=d[fa[j][i-1]][i-1]+d[j][i-1];
    for(int i=1;i<=m;++i) a[i]=read();
    while(l<=r){
        ll mid=l+r>>1;
        if(jud(mid)) r=mid-1,ans=mid;
        else l=mid+1;
    }
    printf("%lld\n",ans);
    return 0;
}

Posted by respecttheplayer on Wed, 22 May 2019 13:02:42 -0700