P1084 NOIP2012T6 epidemic control half the LCA + + greedy

Meaning of the questions: There are multiple nodes in a tree, so that these forces will find all paths from root to leaf nodes by one or more of the army blocked

Since all troops can be moved at the same time, so this problem can be simplified to be: find the longest time to move all the troops, and to minimize the time

Solution: the LCA-half + + greedy

1. bipartite; as given topic data is very large, but also for each approach will be obvious tests are not enough, it is necessary bipartite

2. greedy; any one of the army as long as each step going up, then that army will be able to control a multi-node, so obviously superior; approach: Let each army to go up as much as possible within two minutes of time, this when, can be divided into two cases:

<1> to not root, let it stay there

<2> got to the roots, to record how much time is left in the army

For this second case, if the army is not enough time left to make it return to its roots after the son, and the son of the roots of it through no troops, then let it go back; if the army rest of the time sufficient for it to return, then leave

Next, it will also remain on the roots of the armed forces row a sequence, then the roots of all the sons are still No troops also came a point sequence; the two sequences to compare, you can determine in this time all the epidemic can be brought under control if the army

3.LCA; because every time when half the army after the jump up, is not it obvious to use half of it?

Attach Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N=6e4;

int n,m,t,tot=0,atot=0,btot=0,ctot=0;
int d[N],query[N],f[N][20];
int ver[2*N],edge[2*N],Next[2*N],head[N];
bool ok,sta[N],need[N];
ll ans,tim[N],ned[N],dist[N][20];
pair<ll,int> h[N];
queue<int> q;

void add(int x,int y,int z){
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}

void bfs(){
    q.push(1);
    d[1]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(d[y]) continue;
            d[y]=d[x]+1;
            f[y][0]=x,dist[y][0]=edge[i];
            for(int j=1;j<=21&&y-(1<<j)>=1;j++){
                f[y][j]=f[f[y][j-1]][j-1];
                dist[y][j]=dist[y][j-1]+dist[f[y][j-1]][j-1];
            }
            q.push(y);
        }
    }
}

bool dfs(int x){
    bool pson=0;
    if(sta[x]) return 1;
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        if(d[y]<d[x]) continue;
        pson=1;
        if(!dfs(y)) return 0;
    }
    if(!pson) return 0;
    return 1;
}

bool check(ll lim)
{
    memset(sta,0,sizeof(sta));
    memset(tim,0,sizeof(tim));
    memset(ned,0,sizeof(ned));
    memset(h,0,sizeof(h));
    memset(need,0,sizeof(need));
    atot=0,btot=0,ctot=0;
    for(int i=1;i<=m;i++){
        ll x=query[i],cnt=0;
        for(int j=t;j>=0;j--){
            if(f[x][j]>1&&cnt+dist[x][j]<=lim){
                cnt+=dist[x][j];
                x=f[x][j];
            }
        }
        if(f[x][0]==1&&cnt+dist[x][0]<=lim) h[++ctot]=make_pair(lim-cnt-dist[x][0],x);
        else sta[x]=1;
    }
    for(int i=head[1];i;i=Next[i]) if(!dfs(ver[i])) need[ver[i]]=1;
    sort(h+1,h+ctot+1);
    for(int i=1;i<=ctot;i++){
        if(need[h[i].second]&&h[i].first<dist[h[i].second][0]) need[h[i].second]=0;
        else tim[++atot]=h[i].first;//军队
    }
    for(int i=head[1];i;i=Next[i]) if(need[ver[i]]) ned[++btot]=dist[ver[i]][0];//节点距离 
    if(atot<btot) return 0;
    sort(tim+1,tim+atot+1);
	sort(ned+1,ned+btot+1);
    int i=1,j=1;
    while(i<=btot&&j<=atot){
        if(tim[j]>=ned[i]) i++,j++;
        else j++;
    }
    if(i>btot) return 1;
    return 0;
}

int main()
{
	ll l=0,r=0,mid;
    cin>>n;
    t=log2(n)+1;
    for(int i=1;i<n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
        r+=z;
    }
    bfs();
    cin>>m;
    for(int i=1;i<=m;i++) scanf("%d",&query[i]);
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
            ans=mid;
            ok=true;
        }
        else l=mid+1;
    }
    if(!ok) cout<<-1;
    else cout<<ans;
    return 0;
}

Guess you like

Origin www.cnblogs.com/nnezgy/p/11366559.html