Noip 2013 提高组 货车运输

分析

1.跑出最大生成森林。

2.选取一个超级根,把所有树连接起来。

3.树链剖分,线段树维护最小值。


注意:如果把边上的权值转移到点上,要注意在求值的时候LCA点要不要算上去。


代码


#include
#include
using namespace std;

#define N 100050
#define to e[i].v
#define inf 1000000000

int size[N],head[N],fa[N],val[N],deep[N],pos[N],bl[N],used[N],low[N<<2],vis[N],father[N];
int cnt,id,n,m,sz,k;
struct Node{int u,v,w;}f[N];
struct node{int next,v,w;}e[N];
bool cmp(Node A,Node B){return A.w>B.w;}
void add(int u,int v,int w) {e[id].v=v; e[id].next=head[u]; e[id].w=w; head[u]=id++;}
int min(int a,int b) {return a>b? b:a;}
int swap(int &a,int &b) {int t=a;a=b;b=t;}
int find(int x) {return x==father[x]? x:father[x]=find(father[x]);}

void dfs1(int u)
{
    size[u]=1;
    for (int i=head[u];i;i=e[i].next)
    if (to^fa[u])
    {
        val[to]=e[i].w;
        fa[to]=u;
        deep[to]=deep[u]+1;
        dfs1(to);
        size[u]+=size[to];
    }
}

void dfs2(int u,int chain)
{
    pos[u]=++sz; bl[u]=chain;
    int k=0;
    for (int i=head[u];i;i=e[i].next)
        if (deep[to]>deep[u] && size[to]>size[k]) k=to;
    if (!k) return; dfs2(k,chain);
    for (int i=head[u];i;i=e[i].next)
        if (deep[to]>deep[u] && k^to) dfs2(to,to); 
}

void pushup(int root) {low[root]=min(low[root<<1],low[root<<1|1]);}

void insert(int root,int l,int r,int x,int y)
{
    if (l==r) 
    {
        low[root]=y;
        return;
    }
    int mid=l+r>>1;
    if (x<=mid) insert(root<<1,l,mid,x,y);
    if (mid>1,ans=inf;
    if (L<=mid)  ans=min(ans,query(root<<1,l,mid,L,R));
    if (midpos[y]) swap(x,y);
    ans=min(ans,query(1,1,n,pos[x]+1,pos[y]));
    return ans;
}

int main()
{
    scanf("%d%d",&n,&m); id=1;
    for (int i=1;i<=m;i++)
    {
        int u,v,w; scanf("%d%d%d",&u,&v,&w);
        f[i].u=u; f[i].v=v; f[i].w=w;
    }
    sort(f+1,f+m+1,cmp);
    for (int i=1;i<=n;i++) father[i]=i;
    for (int i=1;i<=m;i++)
    {
        int u=f[i].u,v=f[i].v,w=f[i].w,fu=find(u),fv=find(v);
        if (fu^fv)
        {
            father[fu]=fv;
            add(u,v,w); add(v,u,w);
        }
    }
    for (int i=1;i<=n;i++) int u=find(i);
    int root=++n; 
    for (int i=1;i<=n;i++) vis[father[i]]=1;
    for (int i=1;i<=n;i++) 
        if (vis[i]) add(root,i,inf),add(i,root,inf);
    dfs1(root); dfs2(root,root);
    scanf("%d",&k);val[root]=inf;
    for (int i=1;i<=n;i++) insert(1,1,n,pos[i],val[i]);
    for (int i=1;i<=k;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if (father[u]^father[v]) puts("-1");else printf("%d\n",getmin(u,v));
    }
    return 0;
 } 



你可能感兴趣的:(NOIP)