BZOJ1036: [ZJOI2008]树的统计Count
来源:互联网 发布:双开软件 编辑:程序博客网 时间:2024/04/18 16:37
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
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
树的分治
遥想当年我刚知道BZOJ的时候,迫切想做几道题一展身手,于是就专挑看得懂题面的题来做(无语了),于是。。。那时的我对于这道题交了一个O(n)的纯暴力(当时连时间复杂度都懒得算),而且好像还非常激动得写了个Tarjan求公共祖先,T掉之后愣了好久。。。
言归正传,此题做法:树的分治、树链剖分或动态树,好像还有分块的做法(ORZ)。我看着提示里面写着树的分治然后写了个树链剖分加线段树的做法,然后基本上就是模板了。
一定要注意询问同一个节点的情况(QMAX x x,QSUM x x),可以直接特判来解决。
#include<cstdio>#include<algorithm>#include<cstring>#define INF 2147483647using namespace std;const int N=30100;const int T=5000010;int n,m,q,w[N],point[N],next[2*N],to[2*N];int treenum,nodenum,deep[N],fa[N],son[N],size[N];int rank[N],top[N],belong[N];char opt[20];int root[N],lch[T],rch[T],treemax[T],treesum[T];void add(int u,int v){++m;next[m]=point[u];point[u]=m;to[m]=v;}void dfs(int u){ deep[u]=deep[fa[u]]+1; int tmp=0;size[u]=1; for (int i=point[u];i;i=next[i]) { int v=to[i]; if (v!=fa[u]) { fa[v]=u;dfs(v);size[u]+=size[v]; if (size[v]>tmp){tmp=size[v];son[u]=v;} } } for (int i=point[u];i;i=next[i]) { int v=to[i]; if (v==son[u]) { belong[u]=belong[v]; rank[u]=rank[v]+1; } else top[belong[v]]=v; } if (son[u]==0) { belong[u]=++treenum; rank[u]=1; }}void updata(int now){ treemax[now]=max(treemax[lch[now]],treemax[rch[now]]); treesum[now]=treesum[lch[now]]+treesum[rch[now]];}void build(int now,int l,int r){ treemax[now]=-INF; if (l==r) return; int mid=(l+r)>>1; build(lch[now]=++nodenum,l,mid); build(rch[now]=++nodenum,mid+1,r);}void change(int now,int l,int r,int loc,int v){ if (l==r) { treemax[now]=treesum[now]=v; return; } int mid=(l+r)>>1; if (loc<=mid) change(lch[now],l,mid,loc,v); else change(rch[now],mid+1,r,loc,v); updata(now);}int maxquery(int now,int l,int r,int lrange,int rrange){ if (lrange<=l&&r<=rrange) return treemax[now]; int mid=(l+r)>>1,ans=-INF; if (lrange<=mid) ans=max(ans,maxquery(lch[now],l,mid,lrange,rrange)); if (rrange>mid) ans=max(ans,maxquery(rch[now],mid+1,r,lrange,rrange)); return ans;}int sumquery(int now,int l,int r,int lrange,int rrange){ if (lrange<=l&&r<=rrange) return treesum[now]; int mid=(l+r)>>1,ans=0; if (lrange<=mid) ans+=sumquery(lch[now],l,mid,lrange,rrange); if (rrange>mid) ans+=sumquery(rch[now],mid+1,r,lrange,rrange); return ans;}int maxquery1(int u,int v){ int ans=-INF; while(belong[u]!=belong[v]) { if (deep[top[belong[u]]]>deep[top[belong[v]]]) { ans=max(ans,maxquery(root[belong[u]],1,rank[top[belong[u]]],rank[u],rank[top[belong[u]]])); u=fa[top[belong[u]]]; } else { ans=max(ans,maxquery(root[belong[v]],1,rank[top[belong[v]]],rank[v],rank[top[belong[v]]])); v=fa[top[belong[v]]]; } } ans=max(ans,maxquery(root[belong[u]],1,rank[top[belong[u]]],min(rank[u],rank[v]),max(rank[u],rank[v]))); return ans;}int sumquery1(int u,int v){ int ans=0; while(belong[u]!=belong[v]) { if (deep[top[belong[u]]]>deep[top[belong[v]]]) { ans+=sumquery(root[belong[u]],1,rank[top[belong[u]]],rank[u],rank[top[belong[u]]]); u=fa[top[belong[u]]]; } else { ans+=sumquery(root[belong[v]],1,rank[top[belong[v]]],rank[v],rank[top[belong[v]]]); v=fa[top[belong[v]]]; } } ans+=sumquery(root[belong[u]],1,rank[top[belong[u]]],min(rank[u],rank[v]),max(rank[u],rank[v])); return ans;}void work(){ dfs(1);top[belong[1]]=1; for (int i=1;i<=treenum;++i) { root[i]=++nodenum; build(root[i],1,rank[top[i]]); } for (int i=1;i<=n;++i) change(root[belong[i]],1,rank[top[belong[i]]],rank[i],w[i]);}int main(){ scanf("%d",&n);int x,y; 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",&w[i]); work();scanf("%d",&q); for (;q;--q) { scanf("%s",opt+1);scanf("%d%d",&x,&y); if (opt[1]=='C') change(root[belong[x]],1,rank[top[belong[x]]],rank[x],y); else if (opt[2]=='M') printf("%d\n",maxquery1(x,y)); else printf("%d\n",sumquery1(x,y)); } return 0;}
- [Bzoj1036][ZJOI2008]树的统计Count
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
- 【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题
- 【ZJOI2008】【BZOJ1036】树的统计Count
- [BZOJ1036][ZJOI2008]树的统计Count && LCT
- bzoj1036: [ZJOI2008]树的统计Count
- [BZOJ1036][ZJOI2008]树的统计Count
- 【bzoj1036】【树链剖分】【ZJOI2008】树的统计Count
- 【BZOJ1036】【ZJOI2008】【树的统计count】【树链剖分】
- bzoj1036: [ZJOI2008]树的统计Count
- BZOJ1036: [ZJOI2008]树的统计Count (树链剖分)
- bzoj1036: [ZJOI2008]树的统计Count - 树链剖分
- BZOJ1036: [ZJOI2008]树的统计Count
- bzoj1036【ZJOI2008】树的统计Count
- 【树链剖分】[BZOJ1036][ZJOI2008]树的统计Count
- [BZOJ1036] [ZJOI2008]树的统计Count
- [ZJOI2008] [BZOJ1036] 树的统计Count
- Android: 在UI线程更新UI的几种方式
- 二分查找
- 黑马程序员——Java语言的环境搭建
- leetcode -- Divide Two Integers -- 重点,技巧
- 九度oj 1181 升序链表
- BZOJ1036: [ZJOI2008]树的统计Count
- 随笔一
- Hibernate工程的手动创建
- MySQL存储引擎
- eclipse 连接到数据库
- 注册验证码校验思路
- 《剑指offer》——孩子们的游戏(圆圈中最后剩下的数)
- GPU(CUDA)学习日记(九)------ CUDA存储器模型
- 自定义View步骤