NOIP2018 travel and track construction

A long time ago to fill the pit.

Travel

To a group of n points ring tree, find lexicographically smallest DFS sequence.

n ≤ 5000

answer

O (n- 2 ) practices is obvious that the enumeration broken ring which edge can then greedy. Of course, I was only last year's show operating 88 points.

O (n log n) practices recommended duoluoluo blog.

To delete the ring edge is fixed, we go in the ring when, and only when it is connected to a side of the point, the point number ring largest and bigger than go back to the first point of his father, this time to go back, other times ran DFS normal.

#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
    T x=0,w=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*w;
}
template<class T> T read(T&x){
    return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;

co int N=500000+10;
int n,m;
struct edge {int x,y;}eg[N*2];
il bool operator<(co edge&a,co edge&b){
    return a.y<b.y;
}
vector<int> to[N];

namespace T1{
    int vis[N],ans[N],num;
    
    void dfs(int x){
        vis[x]=1,ans[++num]=x;
        for(int i=0;i<(int)to[x].size();++i){
            int y=to[x][i];
            if(!vis[y]) dfs(y);
        }
    }
    void main(){
        dfs(1);
        for(int i=1;i<=n;++i) printf("%d ",ans[i]);
    }
}

namespace T2{
    int circle,f[N],rings[N];
    int vis[N],ans[N],num;
    int comp,recur;
    
    void dfs_ring(int x,int fa){
        if(circle) return;
        if(!f[x]) f[x]=fa;
        else if(f[x]!=fa){
            for(;fa!=x;fa=f[fa]) rings[fa]=1;
            rings[x]=1,circle=1;
            return;
        }
        for(int i=0;i<(int)to[x].size();++i){
            int y=to[x][i];
            if(y==fa) continue;
            dfs_ring(y,x);
        }
    }
    void dfs_ans(int x){
        vis[x]=1,ans[++num]=x;
        if(!rings[x]){
            for(int i=0;i<(int)to[x].size();++i){
                int y=to[x][i];
                if(vis[y]) continue;
                dfs_ans(y);
            }
            return;
        }
        int found=0;
        for(int i=0;i<(int)to[x].size();++i){
            if(recur) break;
            int y=to[x][i];
            if(vis[y]) continue;
            if(rings[y]){
                int j=i+1;
                while(j<(int)to[x].size() and vis[to[x][j]]) ++j;
                if(j<(int)to[x].size()) comp=to[x][j];
                else if(y>comp) found=1,recur=1;
                break;
            }
        }
        for(int i=0;i<(int)to[x].size();++i){
            int y=to[x][i];
            if(vis[y]) continue;
            if(rings[y] and found) continue;
            dfs_ans(y);
        }
    }
    void main(){
        dfs_ring(1,1);
        comp=INT_MAX,dfs_ans(1);
        for(int i=1;i<=n;++i) printf("%d ",ans[i]);
    }
}

int main(){
    read(n),read(m);
    for(int i=1;i<=m;++i){
        int x=read<int>(),y=read<int>();
        eg[2*i-1]=(edge){x,y},eg[2*i]=(edge){y,x};
    }
    sort(eg+1,eg+2*m+1);
    for(int i=1;i<=2*m;++i) to[eg[i].x].push_back(eg[i].y);
    if(m==n-1) T1::main();
    else T2::main();
    return 0;
}

Track construction

N points to a weighted undirected tree, simply asked to identify the m disjoint path, such that the maximum path length minimum.

n ≤ 50000

answer

Dichotomous answer sentence feasibility. Recommended owencodeisking blog.

For each node, all pass up the value val into a multiset, in fact, these values ​​will contribute to answer two situations:

  1. val≥k
  2. Val A + Val B ≥k

So the first case you can not put multiset, direct answer +1 just fine. The second case can be found for each element in the multiset smallest number in the first ≥k of the two numbers simultaneously deleting, and finally spread to the rest of the maximum value that the father node

After the exam I wonder why this solution is correct, is it possible in some cases for more direct pass the maximum number would answer?

of course not. This number even if only for the great answers contribution plus 1, can be paired with the value of the original node when it did not pass up, only to answer contribution plus 1.

Time complexity of O (log n- 2 n-).

#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
    T x=0,w=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*w;
}
template<class T> T read(T&x){
    return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;

co int N=50000+10;
vector<int> to[N],we[N];
int diameter;

int pretreat(int x,int fa){
    int maxd=0;
    for(int i=0;i<(int)to[x].size();++i){
        int y=to[x][i];
        if(y==fa) continue;
        int len=pretreat(y,x)+we[x][i];
        diameter=max(diameter,maxd+len);
        maxd=max(maxd,len);
    }
    return maxd;
}

int ans;
multiset<int> s[N];
typedef multiset<int>::iterator iter;

int dfs(int x,int fa,int k){
    s[x].clear();
    for(int i=0;i<(int)to[x].size();++i){
        int y=to[x][i];
        if(y==fa) continue;
        int val=dfs(y,x,k)+we[x][i];
        if(val>=k) ++ans;
        else s[x].insert(val);
    }
    int len=0;
    while(s[x].size()){
        if(s[x].size()==1) return max(len,*s[x].begin());
        iter i=s[x].lower_bound(k-*s[x].begin());
        if(i==s[x].begin() and s[x].count(*i)==1) ++i;
        if(i==s[x].end()){
            len=max(len,*s[x].begin());
            s[x].erase(s[x].begin());
        }
        else{
            ++ans;
            s[x].erase(s[x].begin()),s[x].erase(s[x].find(*i)); // edit 1: find
        }
    }
    return len;
}
int check(int k){
    ans=0;
    dfs(1,0,k);
    return ans;
}

int main(){
//  freopen("testdata.in","r",stdin);
    int n=read<int>(),m=read<int>();
    for(int i=1;i<n;++i){
        int x=read<int>(),y=read<int>(),w=read<int>();
        to[x].push_back(y),we[x].push_back(w);
        to[y].push_back(x),we[y].push_back(w);
    }
    pretreat(1,0);
    int l=1,r=diameter;
    while(l<r){
//      cerr<<"l="<<l<<" r="<<r<<endl;
        int mid=(l+r+1)>>1;
        check(mid)>=m?l=mid:r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

Guess you like

Origin www.cnblogs.com/autoint/p/11618474.html