BZOJ 1036 [ZJOI2008]树的统计 Count 题解&代码
2015-12-12 16:54
337 查看
题意:一棵树上有n个节点,编号1到n,每个节点i有权值w[i]。
有三种操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
题目非常浅显易懂= =线段树可以用maxv[]和sum[]保存状态。
change操作就是线段树的单点修改维护
qmax和qsum操作是树链剖分的基本操作了…总之在树上的某一条连续的链上乱搞的八层是树链剖分
关于树链剖分,今天懒得总结= =反正也算是过了两道题了?大致的写法也基本形成了…
嗯,下一道树链剖分一定写总结= =【这是一个机智的flag
**经常把in[x]和x代表的含义搞错= =于是WA了三次,从昨天做到今天
有三种操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
题目非常浅显易懂= =线段树可以用maxv[]和sum[]保存状态。
change操作就是线段树的单点修改维护
qmax和qsum操作是树链剖分的基本操作了…总之在树上的某一条连续的链上乱搞的八层是树链剖分
关于树链剖分,今天懒得总结= =反正也算是过了两道题了?大致的写法也基本形成了…
嗯,下一道树链剖分一定写总结= =【这是一个机智的flag
**经常把in[x]和x代表的含义搞错= =于是WA了三次,从昨天做到今天
#include<iostream> #include<vector> #include<stdio.h> #define lson (o<<1) #define rson ((o<<1)|1) using namespace std; const int maxn=30005; int n,q,fa[maxn],a,b,x,y,tot=0; int maxv[maxn*4],son[maxn],rt[maxn],size[maxn]; int in[maxn],fin[maxn],out[maxn],deep[maxn],v[maxn]; long long ans,sum[maxn*4]; vector <int> edge[maxn]; char s[10]; void dfs(int r,int pre) { fa[r]=pre; size[r]=1; son[r]=-1; deep[r]=deep[pre]+1; for(int i=0;i<edge[r].size();i++) if(edge[r][i]!=pre) { dfs(edge[r][i],r); size[r]+=size[edge[r][i]]; if(son[r]==-1 || size[edge[r][i]]>size[son[r]]) son[r]=edge[r][i]; } } void init(int c,int root) { in[c]=++tot; fin[in[c]]=c; rt[c]=root; if(son[c]==-1)return; init(son[c],root); for(int i=0;i<edge[c].size();i++) if(edge[c][i]!=son[c] && edge[c][i]!=fa[c]) init(edge[c][i],edge[c][i]); out[c]=tot; } void maintain(int o,int l,int r) { if(l!=r) { sum[o]=sum[lson]+sum[rson]; maxv[o]=max(maxv[lson],maxv[rson]); } } void buildtree(int o,int l,int r) { if(l==r) { sum[o]=v[fin[l]]; maxv[o]=v[fin[l]]; return; } int mid=(l+r)/2; buildtree(lson,l,mid); buildtree(rson,mid+1,r); maintain(o,l,r); } void addtree(int o,int l,int r,int L,int R,int c) { if(l>R || r<L)return; if(l==r) { sum[o]=c; maxv[o]=c; return; } int mid=(l+r)/2; addtree(lson,l,mid,L,R,c); addtree(rson,mid+1,r,L,R,c); maintain(o,l,r); } long long getmax(int o,int l,int r,int L,int R) { if(l>R || r<L)return -30005; if(l>=L && r<=R) return maxv[o]; int mid=(l+r)/2; return max(getmax(lson,l,mid,L,R),getmax(rson,mid+1,r,L,R)); } void getsum(int o,int l,int r,int L,int R) { if(l>R || r<L)return; if(l>=L && r<=R) { ans+=sum[o]; return; } int mid=(l+r)/2; getsum(lson,l,mid,L,R); getsum(rson,mid+1,r,L,R); } void findmax(int x,int y) { while(rt[x]!=rt[y]) { if(deep[rt[x]]>deep[rt[y]]) ans=max(ans,getmax(1,1,n,in[rt[x]],in[x])),x=fa[rt[x]]; else ans=max(ans,getmax(1,1,n,in[rt[y]],in[y])),y=fa[rt[y]]; } if(deep[x]>deep[y])ans=max(ans,getmax(1,1,n,in[y],in[x])); else ans=max(ans,getmax(1,1,n,in[x],in[y])); } void findsum(int x,int y) { while(rt[x]!=rt[y]) { if(deep[rt[x]]>deep[rt[y]]) getsum(1,1,n,in[rt[x]],in[x]),x=fa[rt[x]]; else getsum(1,1,n,in[rt[y]],in[y]),y=fa[rt[y]]; } if(deep[x]>deep[y])getsum(1,1,n,in[y],in[x]); else getsum(1,1,n,in[x],in[y]); } int main(void) { scanf("%d",&n); for(int i=2;i<=n;i++) { scanf("%d%d",&a,&b); edge[a].push_back(b); edge[b].push_back(a); } deep[1]=1; dfs(1,0); for(int i=1;i<=n;i++) scanf("%d",&v[i]); init(1,1); buildtree(1,1,n); scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%s",s); scanf("%d%d",&x,&y); if(s[0]=='C') addtree(1,1,n,in[x],in[x],y); else { if(s[1]=='M')ans=-10000005,findmax(x,y); else ans=0,findsum(x,y); printf("%d\n",ans); } } return 0; }
相关文章推荐
- java_48笔记
- php内核探索=opcode
- PHP安全把握整站的结构,避免泄露站点敏感目录
- C# 写入xml文件
- java 字符串格式化方法 String.format()的使用
- VBA 笔记
- 我的小工具,c语言实现模拟POS机补采记录入库
- PHP扩展:第二个程序
- 面向对象和高级编程 20151212
- c语言直接读写ini配置文件
- jmeter初接触-java请求&参数设置
- Storyboard代码跳转的几种方法
- C#_ArrayList的使用方法
- php中关于函数的小知识
- 转载:10个实用的但偏执的Java编程技术
- 无法从 ajax.googleapis.com 下载问题
- C语言链表的理解
- python操作mysql数据库
- Python学习笔记-4(模块:collections、itertools、xml)
- Delphi Edit输入+号(加号),不允许显示输入符号,清空Edit,显示事件