Ch’s gift HDU - 6162 树链剖分

本文介绍了一种解决树状结构中特定路径上节点权值区间求和问题的算法实现。通过深度优先搜索预处理树形结构,并利用线段树进行区间查询优化,实现了高效的查询响应。

题目大意:

有一棵树,n个节点n-1条边,每个节点都有一个权值。然后m次查询输入x,y,a,b意思是从节点到x,y这条路径

上的所有权值在区间[a,b]内的权值和。

分析:自己大概想到了不会超时的方法,但是找不出代码错误。。。(先吧错误代码贴着。。)

int n,m;
int vis[N],val[N];
int son[N],sz[N],fa[N],fst[N],nxt[N<<1],to[N<<1],e;
int label;
int tid[N<<1],top[N],w[N<<2];
int dep[N];

void dfs(int u,int p){
    fa[u]=p;
    sz[u]=1;
    for(int i=fst[u];~i;i=nxt[i]){
        int v=to[i];
        if(v==p)continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v]){ son[u]=v; }
    }
}
void dfs2(int u,int t){
    vis[u]=1;
    top[u]=t;
    tid[u]=++label;
    w[label]=val[u];
    if(son[u])dfs2(son[u],t);
    for(int i=fst[u];~i;i=nxt[i]){
        int v=to[i];
        if(!vis[v])dfs2(v,v);
    }
}
int mi[N<<2],ma[N<<2],sum[N<<2];
void build(int ll,int rr,int i){
    if(ll==rr){
        sum[i]=mi[i]=ma[i]=w[ll];return ;
    }
    build(ll,md,ls),build(md+1,rr,rs);
    mi[i]=min(mi[ls],mi[rs]);
    ma[i]=max(ma[ls],ma[rs]);
    sum[i]=sum[ls]+sum[rs];
}
int query(int ll,int rr,int l,int r,int i,int a,int b){
    if(ll<=l&&r<=rr){
        if(mi[i]>=a&&ma[i]<=b)return sum[i];
        if(mi[i]>b||ma[i]<a)return 0;
        //else return query(ll,md,l,md,ls,a,b)+query(md+1,rr,md+1,r,rs,a,b);
    }
    if(mi[i]>b)return 0;
    if(ma[i]<a)return 0;
    if(r<=md)return query(ll,md,l,md,ls,a,b);
    else if(l>md)   return query(md+1,rr,md+1,r,rs,a,b);
    return query(ll,md,l,md,ls,a,b)+query(md+1,rr,md+1,r,rs,a,b);
}
int calc(int x,int y,int a,int b){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]])swap(x,y);
        ret+=query(tid[top[y]],tid[y],1,n,1,a,b);
        y=fa[top[y]];
    }
    if(x!=y){
        if(dep[x]>dep[y])swap(y,x);
        ret+=query(tid[x],tid[y],1,n,1,a,b);
    }
    else if(x==y){
        if(val[x]>=a&&val[x]<=b)ret+=val[x];
    }
    return ret;
}
void init(){
    dep[1]=sz[0]=0;label=0;
    mem(son,0);mem(fst,-1);mem(vis,0);e=0;mem(vis,0);
}
inline void add(int u,int v){ to[e]=v;nxt[e]=fst[u];fst[u]=e++; }
int main(){
    freopen("in.txt","r",stdin);
    while(~sf("%d%d",&n,&m)){
        init();
        rep(i,1,n)sf("%d",&val[i]);
        rep(i,1,n-1){
            int u,v;sf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1,1);
        dfs2(1,1);
        build(1,n,1);
        while(m--){
            int u,v,a,b;sf("%d%d%d%d",&u,&v,&a,&b);
            pf("%d\n",calc(u,v,a,b));
        }
    }
}

另外,这题数据很水。。看到别人暴力都过了。。。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值