HDU---6547:Tree【树链剖分+线段树】

题面:

HDU---6547:Tree

题意:

给定一颗树,Q次操作,(1)询问树上任意两点之间最短路上点权和(2)将树上任意两点之间最短路上每个点权开根

分析:

树上路径问题树链剖分跑不了,考虑怎样维护区间开根,容易发现0,1开根后不改变值;开根递减的很快,1e9开5次根后再开根就不变了,那么就可以每次暴力更新到叶子节点,并且标记当前子树是否全为0或1,每个叶子节点最多访问5次

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int maxn = 2e5+255;
const int maxm = 1e6+16;
int n,q,u,v,op,a[maxn],cnt,tt,head[maxn];
struct edge{
    int to,nxt;
}e[maxn<<1];
inline int read(){
    int x = 0, f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    return x * f;
}
inline void write(LL x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
inline void addedge(int u,int v){
    e[++cnt] = (edge){v,head[u]};
    head[u] = cnt;
}
int d[maxn],f[maxn],sz[maxn],son[maxn],st[maxn],ed[maxn],b[maxn];
void dfs1(int x,int fa,int depth){
     f[x] = fa; d[x] = depth; 
     sz[x] = 1; st[x] = ++tt; b[tt] = x;
     for(int i = head[x];i;i = e[i].nxt){
        int v = e[i].to;
        if(v == fa) continue;
        dfs1(v,x,depth+1); sz[x] += sz[v];
        if(sz[v] > sz[son[x]]) son[x] = v;
     }
     ed[x] = ++tt; b[tt] = x;
}
int rk[maxn],id[maxn],top[maxn],num;
void dfs2(int x,int Top){
    top[x] = Top; id[x] = ++num;
    rk[num] = x;
    if(!son[x]) return;
    dfs2(son[x],Top);
    for(int i = head[x];i;i = e[i].nxt){
        int v = e[i].to;
        if(v != son[x]&&v != f[x]) dfs2(v,v);
    }
}
/*************以上为树链剖分*************/
LL tr[maxn<<2];
int tag[maxn<<2];
void build(int l,int r,int x){
    if(l == r){
        tr[x] = a[rk[l]];
        return ;
    }
    int mid = (l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
    tr[x] = tr[x<<1] + tr[x<<1|1];
}
void updata(int l,int r,int L,int R,int x){
    if(l > R || r < L) return ;
    if(tag[x]) return ;
    if(l == r){
        tr[x] = floor(sqrt(tr[x]*1.0));
        if(tr[x] == 0 || tr[x] == 1) tag[x] = 1;
        return ;
    }
    int mid = (l+r) >> 1;
    updata(l,mid,L,R,x<<1);
    updata(mid+1,r,L,R,x<<1|1);
    tr[x] = tr[x<<1] + tr[x<<1|1];
    tag[x] = (tag[x<<1]&tag[x<<1|1]);
}
void query(int l,int r,int L,int R,int x,LL &sum){
    if(l > R || r < L) return ;
    if(tr[x] == 0) return ;
    if(l >= L && r <= R){
        sum += tr[x];
        return ;
    }
    int mid = (l+r)>>1;
    query(l,mid,L,R,x<<1,sum);
    query(mid+1,r,L,R,x<<1|1,sum);
}
void updataPath(int u,int v){
    while(top[u] != top[v]){
        if(d[top[u]] < d[top[v]]) swap(u,v);
        updata(1,n,id[top[u]],id[u],1);
        u = f[top[u]];
    }
    if(d[u] > d[v]) swap(u,v);
    updata(1,n,id[u],id[v],1);
}
LL queryPath(int u,int v){
    LL sum = 0;
    while(top[u] != top[v]){
        if(d[top[u]] < d[top[v]]) swap(u,v);
        query(1,n,id[top[u]],id[u],1,sum);
        u = f[top[u]];
    }
    if(d[u] > d[v]) swap(u,v);
    query(1,n,id[u],id[v],1,sum);
    return sum;
}
int main(){
    n = read(), q = read();
    for(int i = 1;i <= n; ++i) a[i] = read();
    for(int i = 1;i < n; ++i) u = read(),v = read(),addedge(u,v),addedge(v,u);
    dfs1(1,0,1); dfs2(1,1); build(1,n,1);
    while(q--){
        op = read(),u = read(),v = read();
        if(op == 0) updataPath(u,v);
        else printf("%I64d\n",queryPath(u,v));
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值