1036: [ZJOI2008]树的统计Count

来源:互联网 发布:数据库服务怎么启动 编辑:程序博客网 时间:2024/06/04 23:23

题目链接

题目大意:给定一棵树,兹磁修改点权,询问两点路径的节点权值和/最大值

题解:树剖裸题,具体见代码

我的收获:树剖第一题……

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define lson l,m,x<<1#define rson m+1,r,x<<1|1#define root 1,n,1 const int M=30005;#define INF 0x3f3f3f3fint n,q,t,tim,x,y;int fa[M],dep[M],son[M],sz[M],top[M],tree[M],pre[M];//树剖相关 int sum[M<<2],mx[M<<2],v[M],head[M];char opt[10];struct edge{int to,nex;}e[M*2];void add(int i,int j){e[t].to=j,e[t].nex=head[i],head[i]=t++;}void dfs(int x)//第一遍dfs,处理出dep,size,fa,son{    sz[x]=1;//叶子的子树大小为1    for(int i=head[x];i!=-1;i=e[i].nex){        int v=e[i].to;        if(v!=fa[x]){            fa[v]=x,dep[v]=dep[x]+1;            dfs(v);sz[x]+=sz[v];            if(!son[x]||sz[v]>sz[son[x]]) son[x]=v;//记录重孩子        }    }}void dfs2(int x,int tp)//连接重边形成重链:以根节点为起点,沿着重边向下拓展,拉成重链,不在当前重链上的节点,都以该节点为起点向下重新拉一条重链。{    top[x]=tp;tree[x]=++tim;//top[v]表示v所在的链的顶端节点,tree[v]表示节点v在线段树中的编号        pre[tree[x]]=x;//pre[v]表示线段树中编号是v的节点所对应的原图中的点(与tree相反)     if(!son[x]) return;    dfs2(son[x],tp);    for(int i=head[x];i!=-1;i=e[i].nex){          int v=e[i].to;         if(v!=son[x]&&v!=fa[x])              dfs2(v,v);//递归轻儿子    }  }//以下是线段树 inline void pushup(int x){sum[x]=sum[x<<1]+sum[x<<1|1];mx[x]=max(mx[x<<1],mx[x<<1|1]);}void build(int l,int r,int x){    if(l==r){mx[x]=sum[x]=v[pre[l]];return ;}//这里注意是pre[l]    int m=(l+r)>>1;    build(lson);build(rson);    pushup(x);}void updata(int p,int v,int l,int r,int x){    if(l==r){mx[x]=sum[x]=v;return ;}    int m=(l+r)>>1;    if(p<=m) updata(p,v,lson);    else updata(p,v,rson);    pushup(x);}int query_sum(int L,int R,int l,int r,int x){    if(L<=l&&r<=R) return sum[x];    int m=(l+r)>>1,ans=0;    if(L<=m) ans+=query_sum(L,R,lson);    if(R>m) ans+=query_sum(L,R,rson);    return ans;}int query_max(int L,int R,int l,int r,int x){    if(L<=l&&r<=R) return mx[x];    int m=(l+r)>>1,ans=-INF;//有负数,所以不能初始化为0    if(L<=m) ans=max(ans,query_max(L,R,lson));    if(R>m) ans=max(ans,query_max(L,R,rson));    return ans;}int find_sum(int x,int y){    int f1=top[x],f2=top[y],ans=0;    while(f1!=f2)//一边查询,一边往一条重链上靠    {        if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);        ans+=query_sum(tree[f1],tree[x],root);        x=fa[f1];f1=top[x];    }    ans+=dep[x]>dep[y]?query_sum(tree[y],tree[x],root):query_sum(tree[x],tree[y],root);//到了同一条重链上    return ans;}int find_max(int x,int y){    int f1=top[x],f2=top[y],ans=-INF;    while(f1!=f2)    {        if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);        ans=max(ans,query_max(tree[f1],tree[x],root));        x=fa[f1];f1=top[x];    }    ans=max(ans,dep[x]>dep[y]?query_max(tree[y],tree[x],root):query_max(tree[x],tree[y],root));    return ans;}void work(){    while(q--)    {        scanf("%s%d%d",opt,&x,&y);        if(opt[0]=='C') updata(tree[x],y,root);        else if(opt[1]=='M') printf("%d\n",find_max(x,y));        else printf("%d\n",find_sum(x,y));    }}void init(){    cin>>n;t=0;    memset(head,-1,sizeof(head));    for(int i=1;i<n;i++){        scanf("%d%d",&x,&y);        add(x,y),add(y,x);    }    for(int i=1;i<=n;i++) scanf("%d",&v[i]);    dfs(1);dfs2(1,1);    build(root);    cin>>q;}int main(){    init();    work();    return 0;}
0 0
原创粉丝点击