[ZJOI2008]树的统计Count
来源:互联网 发布:one软件 编辑:程序博客网 时间:2024/05/29 14:06
Description
一棵树上有
I. CHANGE
II. QMAX
III. QSUM
注意:从点
Input
输入的第一行为一个整数
对于100%的数据,保证
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
HINT
Source
思路
树链剖分模板。
树链剖分不会的请点击这里
代码
#include <cstdio>#include <algorithm>const int maxn=30000;const int inf=1000000000;int n;struct sigment_tree{ private:int maxnum[(maxn<<2)+10],sumnum[(maxn<<2)+10]; private:int updata(int now) { maxnum[now]=std::max(maxnum[now<<1],maxnum[now<<1|1]); sumnum[now]=sumnum[now<<1]+sumnum[now<<1|1]; return 0; } public:int build(int now,int left,int right) { if(left==right) { maxnum[now]=0; sumnum[now]=0; return 0; } int mid=(left+right)>>1; build(now<<1,left,mid); build(now<<1|1,mid+1,right); updata(now); return 0; } public:int modify(int now,int left,int right,int findnum,int changeval) { if((findnum<left)||(findnum>right)) { return 0; } if(left==right) { maxnum[now]=changeval; sumnum[now]=changeval; return 0; } int mid=(left+right)>>1; modify(now<<1,left,mid,findnum,changeval); modify(now<<1|1,mid+1,right,findnum,changeval); updata(now); return 0; } public:int askmax(int now,int left,int right,int askl,int askr) { if((askr<left)||(askl>right)) { return -inf; } if((askl<=left)&&(askr>=right)) { return maxnum[now]; } int mid=(left+right)>>1; return std::max(askmax(now<<1,left,mid,askl,askr),askmax(now<<1|1,mid+1,right,askl,askr)); } public:int asksum(int now,int left,int right,int askl,int askr) { if((askr<left)||(askl>right)) { return 0; } if((askl<=left)&&(askr>=right)) { return sumnum[now]; } int mid=(left+right)>>1; return asksum(now<<1,left,mid,askl,askr)+asksum(now<<1|1,mid+1,right,askl,askr); }};struct tree{ private:int fa[maxn+10],wson[maxn+10],top[maxn+10],dfn[maxn+10],cnt,deep[maxn+10],size[maxn+10]; private:int pre[(maxn<<1)+10],now[maxn+10],son[(maxn<<1)+10],tot; private:sigment_tree st; public:int ins(int a,int b) //将a和b连一条有向边 { tot++; pre[tot]=now[a]; now[a]=tot; son[tot]=b; return 0; } public:int first_dfs(int u,int father) //首次dfs,将deep、fa、size、wson求出来,为第二次dfs做准备 { deep[u]=deep[father]+1; fa[u]=father; size[u]=1; wson[u]=0; int j=now[u]; while(j) { int v=son[j]; if(v!=father) { first_dfs(v,u); size[u]+=size[v]; if((!wson[u])||(size[v]>size[wson[u]])) { wson[u]=v; } } j=pre[j]; } return 0; } public:int second_dfs(int u,int father,int topfather) //第二次dfs,将dfn和top求出来 { cnt++; dfn[u]=cnt; top[u]=topfather; if(wson[u]) //重儿子的top就是当前节点的top { second_dfs(wson[u],u,topfather); } int j=now[u]; while(j) { int v=son[j]; if((v!=father)&&(v!=wson[u])) { second_dfs(v,u,v); } j=pre[j]; } return 0; } public:int change(int pos,int val) //单点修改 { st.modify(1,1,n,dfn[pos],val); //直接修改线段树上这个节点就好 return 0; } public:int askmax(int x,int y) //一条路径上求max值 { int res=-inf; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) { std::swap(x,y); } res=std::max(res,st.askmax(1,1,n,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if(deep[x]>deep[y]) { std::swap(x,y); } //top值相同,那么x和y在同一条重链上 res=std::max(res,st.askmax(1,1,n,dfn[x],dfn[y])); return res; } public:int asksum(int x,int y) //一条路径上求sum值 { int res=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) { std::swap(x,y); } res+=st.asksum(1,1,n,dfn[top[x]],dfn[x]); x=fa[top[x]]; } if(deep[x]>deep[y]) { std::swap(x,y); } res+=st.asksum(1,1,n,dfn[x],dfn[y]); return res; }};tree t;int m;int main(){ scanf("%d",&n); for(int i=1; i<n; i++) { int a,b; scanf("%d%d",&a,&b); t.ins(a,b); t.ins(b,a); } t.first_dfs(1,0); t.second_dfs(1,0,1); for(int i=1; i<=n; i++) { int a; scanf("%d",&a); t.change(i,a); } scanf("%d",&m); while(m--) { char s[7]; int a,b; scanf("%s%d%d",s,&a,&b); if(s[1]=='H') { t.change(a,b); } if(s[1]=='S') { printf("%d\n",t.asksum(a,b)); } if(s[1]=='M') { printf("%d\n",t.askmax(a,b)); } } return 0;}
- [ZJOI2008]树的统计Count
- [ZJOI2008]树的统计Count
- [ZJOI2008]树的统计Count
- [ZJOI2008]树的统计Count
- [ZJOI2008]树的统计Count
- 1036: [ZJOI2008]树的统计Count 树链剖分裸题
- [Bzoj1036][ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
- BZOJ 1036: [ZJOI2008]树的统计Count
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
- 【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题
- 【BZOJ 1036】[ZJOI2008]树的统计Count
- bzoj 1036: [ZJOI2008]树的统计Count
- 【ZJOI2008】【BZOJ1036】树的统计Count
- [BZOJ1036][ZJOI2008]树的统计Count && LCT
- bzoj1036: [ZJOI2008]树的统计Count
- [BZOJ1036][ZJOI2008]树的统计Count
- vue中路由切换动画效果(transition)
- 排序
- 通用块层和SCSI层--I/O处理过程
- 【矩阵快速幂】Experienced Endeavour
- OpenCV 3.3.0+opencv_contirb在VS2015下的配置
- [ZJOI2008]树的统计Count
- 操作票功能
- java的动态代理机制详解
- C#DynamicObject和ExpandoObject用法
- Linux Platform总线+SPI总线分析
- oracle for linux安装报错 file /home/oracle/.Xauthority does not exist
- python下的单例模式
- IO流简介及方法
- 给定俩个字符串一个S(母串),一个T(子串),有多少种方法从母串中移除字符得到子字符串