bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树

来源:互联网 发布:金蝶k3软件多少钱 编辑:程序博客网 时间:2024/06/05 17:33

题目大意:

给你一颗树,每个点有权值,要你求出一个点到另一个点路径的最大权值,或者是权值和,还要支持修改权值的问题。

思路:

树链剖分的模板题。树链剖分大概就是把书上的链给按一定方法拆开,然后每一段去一个hash值,放入线段树中去维护他的区间值。

这里有一个大佬的博客:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

程序:

#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib> #define inf 0x7fffffff#define maxn 30005#define maxm 60005using namespace std;int pos[maxn],top[maxn],fa[maxn],size[maxn],son[maxn],dep[maxn],a[maxn],last[maxn];int n,cnt,sz;struct data{int w,next;}e[maxm];struct tree{int l,r,mx,sum;}t[100001];void add(int u,int v){    e[++cnt].next=last[u]; e[cnt].w=v; last[u]=cnt;    e[++cnt].next=last[v]; e[cnt].w=u; last[v]=cnt;}void init(){    int u,v;    scanf("%d",&n);    for (int i=1;i<=n-1;i++){        scanf("%d%d",&u,&v);        add(u,v);    }    for (int i=1;i<=n;i++){        scanf("%d",&a[i]);    }}void dfs1(int x){    size[x]=1;    for (int i=last[x];i;i=e[i].next){        if (fa[x]==e[i].w) continue;        fa[e[i].w]=x;        dep[e[i].w]=dep[x]+1;        dfs1(e[i].w);        size[x]+=size[e[i].w];    }}void dfs2(int x,int chain){    int k=0;    sz++;    pos[x]=sz;    top[x]=chain;    for (int i=last[x];i;i=e[i].next){        if (fa[x]!=e[i].w&&size[e[i].w]>size[k]) k=e[i].w;    }    if (k==0) return;     dfs2(k,chain);    for (int i=last[x];i;i=e[i].next){        if (e[i].w!=fa[x]&&e[i].w!=k) dfs2(e[i].w,e[i].w);    }}void build(int d,int l,int r){    t[d].l=l;    t[d].r=r;    if (l==r) return;    int mid=(l+r)/2;    build(d*2,l,mid);    build(d*2+1,mid+1,r);}void change(int d,int x,int y){    if (t[d].l==t[d].r) {        t[d].sum=t[d].mx=y;        return;    }    int mid=(t[d].l+t[d].r)/2;    if (x<=mid) change(d*2,x,y);        else change(d*2+1,x,y);    t[d].sum=t[d*2].sum+t[d*2+1].sum;    t[d].mx=max(t[d*2].mx,t[d*2+1].mx);}int querymax(int d,int x,int y){    if (t[d].l==x&&t[d].r==y) return t[d].mx;    int mid=(t[d].l+t[d].r)/2;    if (y<=mid) return querymax(d*2,x,y);    else if (x>mid) return querymax(d*2+1,x,y);    else return max(querymax(d*2,x,mid),querymax(d*2+1,mid+1,y));}int solvemax(int x,int y){    int mx=-inf;    while (top[x]!=top[y]){        if (dep[top[x]]<dep[top[y]]) swap(x,y);        mx=max(mx,querymax(1,pos[top[x]],pos[x]));        x=fa[top[x]];    }    if (dep[x]>dep[y]) swap(x,y);    mx=max(mx,querymax(1,pos[x],pos[y]));    return mx; }int querysum(int d,int x,int y){    if (t[d].l==x&&t[d].r==y) return t[d].sum;    int mid=(t[d].l+t[d].r)/2;    if (y<=mid) return querysum(d*2,x,y);    else if (x>mid) return querysum(d*2+1,x,y);    else return querysum(d*2,x,mid)+querysum(d*2+1,mid+1,y);}int solvesum(int x, int y){    int sum=0;    while (top[x]!=top[y]){        if (dep[top[x]]<dep[top[y]]) swap(x,y);        sum+=querysum(1,pos[top[x]],pos[x]);        x=fa[top[x]];    }    if (dep[x]>dep[y]) swap(x,y);    sum+=querysum(1,pos[x],pos[y]);    return sum;}int solve(){    build(1,1,n);    for (int i=1;i<=n;i++)      change(1,pos[i],a[i]);    int q;    scanf("%d",&q);    char ch[10]; int x,y;    for (int i=1;i<=q;i++){        scanf("%s%d%d",ch,&x,&y);        if (ch[0]=='C') change(1,pos[x],y);        else {            if (ch[1]=='M') printf("%d\n",solvemax(x,y));                else printf("%d\n",solvesum(x,y));        }    }}int main(){    init();    dfs1(1);    dfs2(1,1);    solve();    return 0;}