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
- 1036: [ZJOI2008]树的统计Count 树链剖分裸题
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- 【BZOJ 1036】[ZJOI2008]树的统计Count
- bzoj 1036: [ZJOI2008]树的统计Count
- 1036: [ZJOI2008]树的统计Count
- 1036: [ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008]树的统计Count
- HYSBZ 1036 [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008]树的统计Count
- bzoj 1036 [ZJOI2008]树的统计Count
- 【bzoj】1036: [ZJOI2008]树的统计Count
- 1036: [ZJOI2008]树的统计Count
- [BZOJ]1036: [ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008] 树的统计Count
- 1036: [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- MAC 免密码登录 linux
- KMP算法
- 【黑苹果教程】驱动ATI Radeon HD5450显卡
- 用大盒子套更大的盒子解决问题
- Leetcode 91 - Decode Ways(dp)
- 1036: [ZJOI2008]树的统计Count
- 小弟 正在进行中 未出茅庐 但知道自己的不足 代码的单一没有技术亮点 求大神指点一二
- 12. Integer to Roman
- MySQL学习一
- 去掉集合中的重复元素
- 机器学习中的范数规则化之(二)核范数与规则项参数选择
- 不依赖任何系统API,用c语言实现gbk/utf8/unicode编码转换
- php异常处理
- 模仿游戏throughthefog