[ZJOI2008树的计算]树链剖分

来源:互联网 发布:mac软件更新不了 编辑:程序博客网 时间:2024/05/22 17:29

题目:I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

注意:从点u到点v的路径上的节点包括u和v本身

#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;const int maxn=30010;int to[maxn*2],Next[maxn*2],Begin[maxn],e;void add(int x,int y){    to[++e]=y;    Next[e]=Begin[x];    Begin[x]=e;}int n,cnt;int sz[maxn],son[maxn],top[maxn],fa[maxn];int dep[maxn];int id[maxn],tmp[maxn];int val[maxn*4],Max[maxn*4];int sumans,maxans;void maintain(int o,int l,int r){    Max[o]=max(Max[o<<1],Max[o<<1|1]);    val[o]=val[o<<1]+val[o<<1|1];}void update(int o,int l,int r,int x,int y){    if(l==r){        val[o]=Max[o]=y;        return;    }    int mid=(l+r)>>1;    if(x<=mid) update(o<<1,l,mid,x,y);    else update(o<<1|1,mid+1,r,x,y);    maintain(o,l,r);}void query(int o,int l,int r,int x,int y){    if(x==l && y==r){        maxans=max(maxans,Max[o]);        sumans+=val[o];        return;    }    int mid=(l+r)>>1;    if(y<=mid) query(o<<1,l,mid,x,y);    else if(x>mid) query(o<<1|1,mid+1,r,x,y);    else{        query(o<<1,l,mid,x,mid);        query(o<<1|1,mid+1,r,mid+1,y);    }}void dfs1(int u){    sz[u]=1;    for(int i=Begin[u];i;i=Next[i]){        int v=to[i];        if(v==fa[u]) continue;        dep[v]=dep[u]+1;        fa[v]=u;        dfs1(v);        sz[u]+=sz[v];        if(sz[v]>sz[son[u]]) son[u]=v;    }}void dfs2(int u){    id[u]=++cnt;    update(1,1,n,id[u],tmp[u]);    if(!son[u]) return;    top[son[u]]=top[u];    dfs2(son[u]);    for(int i=Begin[u];i;i=Next[i]){        int v=to[i];        if(id[v]) continue;        top[v]=v;        dfs2(v);    }}void solve(int u,int v){    maxans=-0x3f3f3f3f;    sumans=0;    while(top[u]!=top[v]){        if(dep[top[u]]<dep[top[v]]) swap(u,v);        query(1,1,n,id[top[u]],id[u]);        u=fa[top[u]];    }    if(dep[u]<dep[v]) swap(u,v);    query(1,1,n,id[v],id[u]);}int main(){    scanf("%d",&n);    for(int i=1;i<n;i++){        int a,b;        scanf("%d%d",&a,&b);        add(a,b);        add(b,a);    }    for(int i=1;i<=n;i++) scanf("%d",&tmp[i]);    dep[1]=1;top[1]=1;    dfs1(1);    dfs2(1);    int q;    scanf("%d",&q);    int ans;    while(q--){        char s[20];        int u,v;        scanf("%s%d%d",s,&u,&v);        if(s[1]=='H'){            update(1,1,n,id[u],v);        }else{            solve(u,v);            if(s[1]=='M') ans=maxans;            else ans=sumans;            printf("%d\n",ans);        }    }    return 0;}

^_^

2 1
原创粉丝点击