ZOJ:3649 Social Net

版权声明:原创文章,转载要注明作者哦 https://blog.csdn.net/DYT_B/article/details/81349225

题目描述戳这里
题解:
这题绝对有毒。。。
第一眼看到这题的题面感觉应该比较简单,只要倍增维护一下最大值和最小值就好了???
然而码了70+行之后发现题目读错了。有一个限制条件,两个点x,y是“有向”的,x到y的路径序列中,最大值的位置编号一定要大于最小值的位置编号。。。
这样就比较麻烦了[汗]。
但是也不是不可做,我们“只需要”维护五个倍增数组就可以了。
f [ i ] [ j ] 记录i个祖先
m a x x [ i ] [ j ] 记录i向上推了 2 j 个单位中的最大值。
m i n n [ i ] [ j ] 记录i向上推了 2 j 个单位中的最小值。
m a x x u [ i ] [ j ] 记录i向上推了 2 j 个单位中的最大差值(最大值的深度小于最小值)。
m a x x d [ i ] [ j ] 记录从i向上推了 2 j 个单位的那个点到它的最大差值(最大值的深度大于最小值)。
那么我们假设修正好了这四个数组,那么怎样求答案呢?
给定x,y,我们可以求出x和y的最近公共祖先g,然后就可以求一下左边的maxxu的值,和右边的maxxd的值取个max。考虑到有可能最大值在g到y的路径上,最小值在x到g的路径上,那么只要分别求一下这两个量,然后相减再和原答案取个max即可。
然后我一开始就是这么写的,然后改了半天改不出错。。。
无奈之下只好对拍,最后发现写出了点偏差。。。
我们在求出左边的maxxu值的时候因为是用倍增跳的,这样会导致只求出了某一些向 2 j 个单位的答案。但是考虑到有跨过一块的情况,我们要在倍增时修正一下当前最大值或最小值,这样就能避免少算。

那么具体怎么修正这四个倍增数组,和前面倍增的过程差不多,修正一下左边和右边,然后在中间合并一下就好了。

代码如下:

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=30005,maxm=50005;
int n,m,Q,tot,b[maxn],lnk[maxn],son[2*maxn],nxt[2*maxn],fa[maxn],dep[maxn];
int f[maxn][21],maxx[maxn][21],maxxu[maxn][21],maxxd[maxn][21],minn[maxn][21];
ll sum;
struct dyt{
    int x,y,w;
    bool operator <(const dyt &b) const{return w>b.w;}
}a[maxm];
void add(int x,int y){son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
int getfa(int x){if (fa[x]!=x) fa[x]=getfa(fa[x]); return fa[x];}
void clear(){
    tot=0; sum=0;
    memset(f,0,sizeof(f));
    memset(fa,0,sizeof(fa));
    memset(minn,63,sizeof(minn));
    memset(maxx,0,sizeof(maxx));
    memset(maxxu,0,sizeof(maxxu));
    memset(maxxd,0,sizeof(maxxd));
    memset(lnk,0,sizeof(lnk));
    memset(nxt,0,sizeof(nxt));
    memset(dep,0,sizeof(dep));
}
void dfs(int x,int las){
    for (int j=lnk[x];j;j=nxt[j])
    if (las!=son[j]) {
        f[son[j]][0]=x; dep[son[j]]=dep[x]+1;
        maxx[son[j]][0]=max(b[x],b[son[j]]); minn[son[j]][0]=min(b[x],b[son[j]]);
        maxxu[son[j]][0]=max(0,b[x]-b[son[j]]); maxxd[son[j]][0]=max(0,b[son[j]]-b[x]);
        dfs(son[j],x);
    }
}
void make_(){
    for (int j=1;j<=20;j++)
    for (int i=1;i<=n;i++) {
        f[i][j]=f[f[i][j-1]][j-1];
        minn[i][j]=min(minn[i][j-1],minn[f[i][j-1]][j-1]);
        maxx[i][j]=max(maxx[i][j-1],maxx[f[i][j-1]][j-1]);
        maxxu[i][j]=max(0,max(max(maxxu[i][j-1],maxxu[f[i][j-1]][j-1]),maxx[f[i][j-1]][j-1]-minn[i][j-1]));
        maxxd[i][j]=max(0,max(max(maxxd[i][j-1],maxxd[f[i][j-1]][j-1]),maxx[i][j-1]-minn[f[i][j-1]][j-1]));
    }
}
int get(int x,int y){
    if (dep[x]<dep[y]) swap(x,y);
    for (int j=20;j>=0;j--)
    if (dep[f[x][j]]>=dep[y]) x=f[x][j];
    if (x==y) return y;
    for (int j=20;j>=0;j--)
    if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
    return f[x][0];
}
int getans(int x,int y){
    int ret=0;
    if (dep[x]>dep[y]){
        int mn=1<<30;
        for (int j=20;j>=0;j--)
            if (dep[f[x][j]]>=dep[y]) {
                ret=max(ret,maxx[x][j]-mn); mn=min(mn,minn[x][j]);
                ret=max(ret,maxxu[x][j]),x=f[x][j];
            }
    } else {
        int mx=0;
        for (int j=20;j>=0;j--)
            if (dep[f[y][j]]>=dep[x]) {
                ret=max(ret,mx-minn[y][j]); mx=max(mx,maxx[y][j]);
                ret=max(ret,maxxd[y][j]),y=f[y][j];
            }
    }
    return ret;
}
int getans1(int x,int y,int grand){
    if (x==grand||y==grand) return 0;
    int mxx=0,mnn=1<<30;
    for (int j=20;j>=0;j--)
        if (dep[f[x][j]]>=dep[grand]) mnn=min(mnn,minn[x][j]),x=f[x][j];
    for (int j=20;j>=0;j--)
        if (dep[f[y][j]]>=dep[grand]) mxx=max(mxx,maxx[y][j]),y=f[y][j];
    return max(0,mxx-mnn);
}
int main(){
    while (~scanf("%d",&n)) {
        clear();
        for (int i=1;i<=n;i++) fa[i]=i,scanf("%d",&b[i]);
        scanf("%d",&m);
        for (int i=1;i<=m;i++) scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].w);
        sort(a+1,a+1+m);
        for (int i=1;i<=m;i++) {
            int fax=getfa(a[i].x),fay=getfa(a[i].y);
            if (fax!=fay) {
                sum+=1ll*a[i].w; fa[fax]=fay;
                add(a[i].x,a[i].y); add(a[i].y,a[i].x);
            }
        }
        printf("%lld\n",sum);
        maxx[1][0]=b[1]; minn[1][0]=b[1]; dep[1]=1;
        dfs(1,0); make_();
        scanf("%d",&Q);
        while (Q--) {
            int x,y;
            scanf("%d %d",&x,&y);
            int grand=get(x,y);
            printf("%d\n",max(0,max(max(getans(x,grand),getans(grand,y)),getans1(x,y,grand))));
        }
    }
    return 0;
}

我的博客

猜你喜欢

转载自blog.csdn.net/DYT_B/article/details/81349225