2012-A3-0019

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

题目大意:一张带有边权和点权的图,要从这个图求一个net,题目保证这个net唯一,这个net要用最少的边数,然后还要最大的边权和,似乎还要保证所有点联通.

于是大概是个最大生成树,然后给出若干询问,从X走到Y(不走回头路),按顺序经过的点权,先选个小的,再选个大的,使大的和小的的差最大,

如果点权依次递减或平,根据样例则是输出0.



那么就先根据题意求个MaximumSpanningTree,

树上的路径是唯一的,于是在无根树里任选个点作为根,使之成为一个有根树,询问X到Y的路径,就是询问XY的LCA,

路径就是X->LCA(X,Y)->Y.然后可以在建立有根树和求LCA的过程维护一些域

z到某个祖先的路径上的答案,那个祖先到z的路径上的答案,这条路径上的点权最大值,和最小值.

然后如果已经求出,z到某个祖先A(z)的上述域,和A(z)到它的某祖先A(A(z))的上述域,就可以通过二者求出z 到A(A(z))的上述域.

可以倍增求出2^k^次阶祖先,然后在log,,2,,n的复杂度里合并路径求出到任意祖先的上述域.

然后通过求LCA,在合并求出的路径得出最后的答案

x到y,的答案就是 MAX{(x到LCA(x,y)的答案),(LCA(x,y)到y的答案),(LCA到y上的最大值-x到LCA(x,y)的最小值)}

{{{
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef unsigned u32;
#define go(i,n) for(u32 i=0;i<(n);++i)
pair<u32,u32> ed[51200];
vector<u32> e[32768];
u32 f[32768],r[32768];
u32 ff(u32 x){return x!=f[x]?f[x]=ff(f[x]):x;}
struct {u32 ac;int x,y,mx,mn;}o[30000][16];
void dfs(u32 u,u32 uf){
    f[u]=f[uf]+1;
    u32 ac=o[u][0].ac=uf;
    o[u][0].mx=max(r[u],r[ac]);
    o[u][0].mn=min(r[u],r[ac]);
    o[u][0].x=max(0,(int)(r[ac]-r[u]));
    o[u][0].y=max(0,(int)(r[u]-r[ac]));
    go(i,14){
        o[u][i+1].mx=max(o[ac][i].mx,o[u][i].mx);
        o[u][i+1].mn=min(o[ac][i].mn,o[u][i].mn);
        o[u][i+1].x=max(max(o[u][i].x,o[ac][i].x),o[ac][i].mx-o[u][i].mn);
        o[u][i+1].y=max(max(o[u][i].y,o[ac][i].y),o[u][i].mx-o[ac][i].mn);
        ac=o[u][i+1].ac=o[ac][i].ac;
    }
    go(i,e[u].size())if(e[u][i]!=uf)
        dfs(e[u][i],u);
}
int main(){
    srand(time(0));
    for(u32 n,m,a,b,c,mst;scanf("%u",&n)==1;){
        go(i,n)scanf("%u",r+i);
        scanf("%u",&m);
        go(i,m){
            scanf("%u%u%u",&a,&b,&c);
            ed[i]= make_pair(-c,--a<<16|--b);
        }
        go(i,n){f[i]=i;e[i].clear();}
        sort(ed,ed+m);mst=0;
        go(i,m)
        if(ff(a=ed[i].second>>16)!=ff(b=ed[i].second&65535)){
            e[a].push_back(b);
            e[b].push_back(a);
            mst-=ed[i].first;
            f[ff(b)]=ff(a);
        }
        printf("%u\n",mst);
        f[c = rand()%n]=0;//printf("root==%u\n",c);
        dfs(c,c);
        scanf("%u",&m);
        for(int mx,mn,as;m--;printf("%d\n",max(as,mx-mn))){
            scanf("%u%u",&a,&b);
            mn=r[--a];mx=r[--b];as=0;
            for(u32 t;f[a]>f[b];a=o[a][t].ac){
                t=__builtin_ctz(f[b]-f[a]);
                as = max(as,max(o[a][t].x,o[a][t].mx-mn));
                mn = min(mn,o[a][t].mn);
            }
            for(u32 t;f[b]>f[a];b=o[b][t].ac){
                t=__builtin_ctz(f[a]-f[b]);
                as = max(as,max(o[b][t].y,mx-o[b][t].mn));
                mx = max(mx,o[b][t].mx);
            }
            if(a!=b){
                for(u32 i=15;i--;)
                if(o[a][i].ac!=o[b][i].ac){
                    as=max(as,max(max(o[a][i].mx-mn,mx-o[b][i].mn),max(o[a][i].x,o[b][i].y)));
                    mn=min(mn,o[a][i].mn);
                    mx=max(mx,o[b][i].mx);
                    a=o[a][i].ac;b=o[b][i].ac;
                }
                as=max(as,max(o[a][0].x,o[b][0].y));
                mn=min(mn,o[a][0].mn);
                mx=max(mx,o[b][0].mx);
            }
        }
    }
}
}}}

题目大意:一张带有边权和点权的图,要从这个图求一个net,题目保证这个net唯一,这个net要用最少的边数,然后还要最大的边权和,似乎还要保证所有点联通.

于是大概是个最大生成树,然后给出若干询问,从X走到Y(不走回头路),按顺序经过的点权,先选个小的,再选个大的,使大的和小的的差最大,

如果点权依次递减或平,根据样例则是输出0.

那么就先根据题意求个MaximumSpanningTree,

树上的路径是唯一的,于是在无根树里任选个点作为根,使之成为一个有根树,询问X到Y的路径,就是询问XY的LCA,

路径就是X->LCA(X,Y)->Y.然后可以在建立有根树和求LCA的过程维护一些域

z到某个祖先的路径上的答案,那个祖先到z的路径上的答案,这条路径上的点权最大值,和最小值.

然后如果已经求出,z到某个祖先A(z)的上述域,和A(z)到它的某祖先A(A(z))的上述域,就可以通过二者求出z 到A(A(z))的上述域.

可以倍增求出2k次阶祖先,然后在log2n的复杂度里合并路径求出到任意祖先的上述域.

然后通过求LCA,在合并求出的路径得出最后的答案

x到y,的答案就是 MAX{(x到LCA(x,y)的答案),(LCA(x,y)到y的答案),(LCA到y上的最大值-x到LCA(x,y)的最小值)}

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef unsigned u32;
#define go(i,n) for(u32 i=0;i<(n);++i)
pair<u32,u32> ed[51200];
vector<u32> e[32768];
u32 f[32768],r[32768];
u32 ff(u32 x){return x!=f[x]?f[x]=ff(f[x]):x;}
struct {u32 ac;int x,y,mx,mn;}o[30000][16];
void dfs(u32 u,u32 uf){
    f[u]=f[uf]+1;
    u32 ac=o[u][0].ac=uf;
    o[u][0].mx=max(r[u],r[ac]);
    o[u][0].mn=min(r[u],r[ac]);
    o[u][0].x=max(0,(int)(r[ac]-r[u]));
    o[u][0].y=max(0,(int)(r[u]-r[ac]));
    go(i,14){
        o[u][i+1].mx=max(o[ac][i].mx,o[u][i].mx);
        o[u][i+1].mn=min(o[ac][i].mn,o[u][i].mn);
        o[u][i+1].x=max(max(o[u][i].x,o[ac][i].x),o[ac][i].mx-o[u][i].mn);
        o[u][i+1].y=max(max(o[u][i].y,o[ac][i].y),o[u][i].mx-o[ac][i].mn);
        ac=o[u][i+1].ac=o[ac][i].ac;
    }
    go(i,e[u].size())if(e[u][i]!=uf)
        dfs(e[u][i],u);
}
int main(){
    srand(time(0));
    for(u32 n,m,a,b,c,mst;scanf("%u",&n)==1;){
        go(i,n)scanf("%u",r+i);
        scanf("%u",&m);
        go(i,m){
            scanf("%u%u%u",&a,&b,&c);
            ed[i]= make_pair(-c,--a<<16|--b);
        }
        go(i,n){f[i]=i;e[i].clear();}
        sort(ed,ed+m);mst=0;
        go(i,m)
        if(ff(a=ed[i].second>>16)!=ff(b=ed[i].second&65535)){
            e[a].push_back(b);
            e[b].push_back(a);
            mst-=ed[i].first;
            f[ff(b)]=ff(a);
        }
        printf("%u\n",mst);
        f[c = rand()%n]=0;//printf("root==%u\n",c);
        dfs(c,c);
        scanf("%u",&m);
        for(int mx,mn,as;m--;printf("%d\n",max(as,mx-mn))){
            scanf("%u%u",&a,&b);
            mn=r[--a];mx=r[--b];as=0;
            for(u32 t;f[a]>f[b];a=o[a][t].ac){
                t=__builtin_ctz(f[b]-f[a]);
                as = max(as,max(o[a][t].x,o[a][t].mx-mn));
                mn = min(mn,o[a][t].mn);
            }
            for(u32 t;f[b]>f[a];b=o[b][t].ac){
                t=__builtin_ctz(f[a]-f[b]);
                as = max(as,max(o[b][t].y,mx-o[b][t].mn));
                mx = max(mx,o[b][t].mx);
            }
            if(a!=b){
                for(u32 i=15;i--;)
                if(o[a][i].ac!=o[b][i].ac){
                    as=max(as,max(max(o[a][i].mx-mn,mx-o[b][i].mn),max(o[a][i].x,o[b][i].y)));
                    mn=min(mn,o[a][i].mn);
                    mx=max(mx,o[b][i].mx);
                    a=o[a][i].ac;b=o[b][i].ac;
                }
                as=max(as,max(o[a][0].x,o[b][0].y));
                mn=min(mn,o[a][0].mn);
                mx=max(mx,o[b][0].mx);
            }
        }
    }
}