POJ3162 Walking Race

描述:

飞老鼠(什么鬼。。)的姐姐wc擅长运动,她最喜欢的项目是竞走。.... ̄へ ̄....她来到一个训练中心参加训练。这个中心有N个节点(从1到N)。某些对节点之间有一条无向边相连,这些节点和无向边构成一棵树。训练持续N天。在第i天,wc选节点i作为出发点,选另一个节点作为终点然后沿着两点之间的路径开始走啊走。。他所选择的终点会使路径尽可能地长。

在每天的训练结束后,飞老鼠将会做一些身体检查,这些数据会被收集起来用作分析,为他提供更好的训练指导。为了使数据可信,飞老鼠不会使用这N天的所有数据,他的分析模型只需要连续的一段时间的数据,这段时间里他每天所走的最长距离与最短距离不能超过M。用作分析的天数越多,结果就越精确。飞老鼠想要知道最多能分析多少天的数据。。

输入:

还有一组数据(°o°;),第一行两个整数N(N<=1e6),M(M<1e9)。接下来的N-1行,每行两个数fi,di,表示节点i+1与节点fi之间有条权值为di的无向边相连。

输出:

输出答案为最长多少天。

分析:

我英语没学好。。

问题分为两部分,一是求出树中每个节点出发所能走的最远距离,或者是从某个点到叶节点的最远距离。二是求一个数组中最大值与最小值之差不超过M的最长序列的长度。

其实两个问题都不难。

对于第一个问题,我们可以维护四个数组:dp1表示最终求出来的某节点到其余节点的最远距离,dp2表示相应的次远距离,type表示节点最远距离的类型(true表示经过其最长子链,false表示经过其父节点的最长子链,son表示每个节点的最长子链的起始点(即相应的孩子节点))。然后两趟dfs,第一趟求出dp1(暂时表示为其最长子链的长度),dp2,son。第二趟按先序处理dp1和type,已知根节点1肯定是type[1]=true,dp1也不用修改,这是初始条件。然后由于每次dfs处理的点的type已知(由初始条件),如果type[key]==false,那么对每个孩子节点v有dp1[v]=G[key][i].w+dp1[key],type[v]=false;如果type[key]==true,对于非最长子链的起始点,仍有:dp1[v]=G[key][i].w+dp1[key],type[v]=false,对于最长子链的起始点v,如果dp1[v]<=G[key][i].w+dp2[key],则type[v]=false,dp1[v]=G[key][i].w+dp2[key],如果dp1[v]>G[key][i].w+dp2[key],则dp1[v]不变,type[v]=true,dp2[v]=max(dp2[v],G[key][i].w+dp2[key])。。。最后dp1[i]就表示节点i所能到达的最远距离。

第二个问题,是一个RMQ问题。我用了RMQ查询(预处理O(nlgn),单次查询O(1),空间复杂度O(nlgn))和线段树查询(预处理O(nlgn),单次查询O(lgn),空间复杂度O(n)),结果一个MLE一个TLE(应该是我写搓了)。于是我上网搜了单调队列法,O(n)解决。。

关于单调队列,就是说使[id,i]区间内的最大值(或最小值)放在队首举个例子,考虑数组:8,3,4,6,9,1,2,7,5,6,10

总时间复杂度:O(n)

dfs加单调队列,48188K,2391ms。

代码:

#include<cstdio>
using namespace std;
#define N 1000005
#define max(x,y) (x<y?y:x)
#define min(x,y) (x>y?y:x)
struct Edge{
    int to,w;
    Edge* next;
};
Edge edge[N<<1],*pedge[N];  //为了不用STL,这里用边集存储,to,w分别是边的终点(把无向边看成两个有向边)和权值,next是下一个边的指针,pedge[i]表示节点i所指向的边,在这里pedge[i]引出一条边链
struct Node{
    int v,d;
};
Node minn[N],maxx[N];   //v表示最远距离,d表示相应的点的索引
int dp1[N],dp2[N],son[N],n,m,cnt;   
bool type[N];
void addedge(int u,int v,int w){
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pedge[u];
    pedge[u]=&edge[cnt++];
}
void dfs1(int key,int fa){
    son[key]=dp1[key]=dp2[key]=0;int v;
    for(Edge* p=pedge[key];p;p=p->next){
        if((v=p->to)==fa) continue;
        dfs1(v,key);
        if(dp1[v]+p->w>dp1[key]){son[key]=v;dp2[key]=dp1[key];dp1[key]=dp1[v]+p->w;}
        else {dp2[key]=max(dp2[key],dp1[v]+p->w);}
    }
}
void dfs2(int key,int fa){
    int v;
    for(Edge* p=pedge[key];p;p=p->next){
        if((v=p->to)==fa) continue;
        if(type[key]==false||v!=son[key]){
            type[v]=false;dp1[v]=dp1[key]+p->w;
        }
        else{
            if(dp1[v]<p->w+dp2[key]){
                dp1[v]=p->w+dp2[key];type[v]=false;
            }
            else{
                type[v]=true;dp2[v]=max(dp2[v],p->w+dp2[key]);
            }
        }
        if(son[v]!=0) dfs2(v,key);
    }
}
int main(){
    int v,d,ans,id,maxl,maxr,minl,minr;
    while(scanf("%d%d",&n,&m)!=EOF){cnt=0;
        for(int i=1;i<=n;++i) pedge[i]=0;
        for(int i=2;i<=n;++i){
            scanf("%d%d",&v,&d);
            addedge(i,v,d);addedge(v,i,d);
        }ans=0;id=1;maxl=minl=maxr=minr=0;
        dfs1(1,0);type[1]=true;dfs2(1,0);
        for(int i=1;i<=n;++i){
            while(maxl<maxr&&maxx[maxr-1].v<dp1[i]) --maxr;maxx[maxr].v=dp1[i];maxx[maxr++].d=i;
            while(minl<minr&&minn[minr-1].v>dp1[i]) --minr;minn[minr].v=dp1[i];minn[minr++].d=i;
            while(id<=i){
                if(maxx[maxl].v-minn[minl].v<=m) break;++id;
                while(maxl<maxr&&maxx[maxl].d<id) ++maxl;
                while(minl<minr&&minn[minl].d<id) ++minl;
            }
            ans=max(ans,i-id+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}
后来有大神说是POJ上用STL的list和vector特别慢所以才TLE的。。这里把相应的代码也贴一下Orz

dfs加线段树,TLE。。。

代码:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define N 1000005
#define M 1<<30
#define max(x,y) (x<y?y:x)
#define min(x,y) (x>y?y:x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct Node{
    int v,d;
    Node(int v,int d):v(v),d(d){}
};
vector<Node> G[N];
int dp1[N],dp2[N],son[N],ma[N<<2],mi[N<<2],n,m,minn,maxx;
bool type[N];
void dfs1(int key,int fa){
    son[key]=dp1[key]=dp2[key]=0;int v;
    for(unsigned int i=0;i<G[key].size();++i){
        if((v=G[key][i].v)==fa) continue;
        dfs1(v,key);
        if(dp1[v]+G[key][i].d>dp1[key]){son[key]=v;dp2[key]=dp1[key];dp1[key]=dp1[v]+G[key][i].d;}
        else {dp2[key]=max(dp2[key],dp1[v]+G[key][i].d);}
    }
}
void dfs2(int key,int fa){
    int v;
    for(unsigned int i=0;i<G[key].size();++i){
        if((v=G[key][i].v)==fa) continue;
        if(type[key]==false||v!=son[key]){
            type[v]=false;dp1[v]=dp1[key]+G[key][i].d;
        }
        else{
            if(dp1[v]<G[key][i].d+dp2[key]){
                dp1[v]=G[key][i].d+dp2[key];type[v]=false;
            }
            else{
                type[v]=true;dp2[v]=max(dp2[v],G[key][i].d+dp2[key]);
            }
        }
        if(son[v]!=0) dfs2(v,key);
    }
}
inline void plusup(int rt){
    ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);
    mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l==r){ma[rt]=mi[rt]=dp1[l];return;}
    int m=(l+r)>>1;
    build(lson);build(rson);
    plusup(rt);
}
void query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){maxx=max(maxx,ma[rt]);minn=min(minn,mi[rt]);return;}
    int m=(l+r)>>1;
    if(L<=m) query(L,R,lson);
    if(R>m) query(L,R,rson);
}
int main(){
    int v,d,ans,id;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;++i) G[i].clear();
        for(int i=2;i<=n;++i){
            scanf("%d%d",&v,&d);
            G[i].push_back(Node(v,d));
            G[v].push_back(Node(i,d));
        }ans=0;id=1;
        dfs1(1,0);type[1]=true;dfs2(1,0);build(1,n,1);
        for(int i=1;i<=n;++i){
            while(id<=i){
                maxx=-1;minn=M;
                query(id,i,1,n,1);
                if(maxx-minn<=m) break;
                else ++id;
            }
            ans=max(ans,i-id+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

dfs加RMQ查询,MLE。。。

代码:

#include<cstdio>
#include<cstring>
#include<list>
#include<cmath>
using namespace std;
#define N 1000005
#define eps 1e-6
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
struct Node{
    int v,d;
    Node(int v,int d):v(v),d(d){}
};
list<Node> G[N];
int dp1[N],dp2[N],son[N],ma[N][25],mi[N][25],mm[N],n,m;
bool type[N];
void dfs1(int key,int fa){
    son[key]=dp1[key]=dp2[key]=0;int v;
    for(list<Node>::const_iterator it=G[key].begin();it!=G[key].end();++it){
        if((v=it->v)==fa) continue;
        dfs1(v,key);
        if(dp1[v]+it->d>dp1[key]){son[key]=v;dp2[key]=dp1[key];dp1[key]=dp1[v]+it->d;}
        else {dp2[key]=max(dp2[key],dp1[v]+it->d);}
    }
}
void dfs2(int key,int fa){
    int v;
    for(list<Node>::const_iterator it=G[key].begin();it!=G[key].end();++it){
        if((v=it->v)==fa) continue;
        if(type[key]==false||v!=son[key]){
            type[v]=false;dp1[v]=dp1[key]+it->d;
        }
        else{
            if(dp1[v]<it->d+dp2[key]){
                dp1[v]=it->d+dp2[key];type[v]=false;
            }
            else{
                type[v]=true;dp2[v]=max(dp2[v],it->d+dp2[key]);
            }
        }
        if(son[v]!=0) dfs2(v,key);
    }
}
void initRMQ(){
    int val1,val2,len=(int)(log(n)/log(2)+eps);
    for(int i=1;i<=n;++i){ma[i][0]=mi[i][0]=dp1[i];}
    for(int i=1;i<=len;++i){
        val1=n-(1<<i)+1;val2=(1<<(i-1));
        for(int j=1;j<=val1;++j){
            ma[j][i]=max(ma[j][i-1],ma[j+val2][i-1]);
            mi[j][i]=min(mi[j][i-1],mi[j+val2][i-1]);
        }
    }
}
int main(){
    int v,d,tmp,k,ans,id;mm[1]=0;tmp=2;
    for(int i=2;i<N;++i){
        if(i>=tmp){mm[i]=mm[i-1]+1;tmp=(tmp<<1);}
        else mm[i]=mm[i-1];
    }
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;++i) G[i].clear();
        for(int i=2;i<=n;++i){
            scanf("%d%d",&v,&d);
            G[i].push_back(Node(v,d));
            G[v].push_back(Node(i,d));
        }ans=0;id=1;
        dfs1(1,0);type[1]=true;dfs2(1,0);initRMQ();
        for(int i=1;i<=n;++i){
            k=mm[i-id+1];
            while(max(ma[id][k],ma[i-(1<<k)+1][k])-min(mi[id][k],mi[i-(1<<k)+1][k])>m) ++id;
            ans=max(ans,i-id+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

七发TLE+两发MLE+两发WA,最终换来了一发AC。。。QAQ我好菜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值