BZOJ 3531 旅行 (树链剖分 + 线段树动态开点)
2018-01-28 13:13
387 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531;
题目大意:中文题就不解释题意了~(-,-)
题目思路:这种树上两点链上查询的题目一眼就是树链剖分了,但是由于是要查询一条链上相同宗教的值,所以就不好用普通的线段树去维护,一开始是想开C棵线段树,最后理智还是战胜了冲动。去查题解,才发现线段树还有动态开点这种操作。
我们正常的线段树某个根节点rt的左儿子的编号是rt<<1,右儿子的编号是rt<<1|1,而动态开线段树的话我们是一边存储一边给左右儿子编号,用root[c]来记录信仰宗教为c的城市的线段树的根节点,每次查询只查询相应点宗教那棵树上的值就行了,记得在修改宗教的时候要把原先那个宗教中的线段树的值变为0,还有就是w和c要一起更新,剩下的就是树链剖分和线段树的常规操作了,具体实现看代码吧。
题目大意:中文题就不解释题意了~(-,-)
题目思路:这种树上两点链上查询的题目一眼就是树链剖分了,但是由于是要查询一条链上相同宗教的值,所以就不好用普通的线段树去维护,一开始是想开C棵线段树,最后理智还是战胜了冲动。去查题解,才发现线段树还有动态开点这种操作。
我们正常的线段树某个根节点rt的左儿子的编号是rt<<1,右儿子的编号是rt<<1|1,而动态开线段树的话我们是一边存储一边给左右儿子编号,用root[c]来记录信仰宗教为c的城市的线段树的根节点,每次查询只查询相应点宗教那棵树上的值就行了,记得在修改宗教的时候要把原先那个宗教中的线段树的值变为0,还有就是w和c要一起更新,剩下的就是树链剖分和线段树的常规操作了,具体实现看代码吧。
#include <bits/stdc++.h> using namespace std; const int MX = 1e5+7; struct edge{int v,nxt;}E[MX<<1]; int head[MX],tot; int n,q,cnt,tmp; int w[MX],c[MX]; int sz[MX],son[MX],fa[MX],dep[MX],top[MX],id[MX]; int root[MX];//记录不同宗教的线段树的根节点 struct tree{ int sum,MAX; int ls,rs; }T[MX*40];//数组记得开大点,因为要调用的空间很多,一开始开小一直RE void init(){ memset(head,-1,sizeof(head)); tot = cnt = tmp = 0; } void add_edge(int u,int v){ E[tot].v = v;E[tot].nxt = head[u]; head[u] = tot++; E[tot].v = u;E[tot].nxt = head[v]; head[v] = tot++; } void dfs1(int u){ sz[u] = 1;son[u] = 0; for(int i = head[u];~i;i = E[i].nxt){ int v = E[i].v; if(v == fa[u]) continue; fa[v] = u;dep[v] = dep[u] + 1; dfs1(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } void dfs2(int u,int tp){ id[u] = ++cnt; top[u] = tp; if(son[u]) dfs2(son[u],tp); for(int i = head[u];~i;i = E[i].nxt){ int v = E[i].v; if(v == fa[u] || v == son[u]) continue; dfs2(v,v); } } void push_up(int rt){ T[rt].sum = T[T[rt].ls].sum + T[T[rt].rs].sum; T[rt].MAX = max(T[T[rt].ls].MAX,T[T[rt].rs].MAX); } void update(int p,int x,int l,int r,int &rt){ //rt记得加&,因为是一边存储一边更新结点编号的 if(!rt) rt = ++tmp; if(l == r){ T[rt].sum = T[rt].MAX = x; return; } int m = (l + r) >> 1; if(p <= m) update(p,x,l,m,T[rt].ls); else update(p,x,m+1,r,T[rt].rs); push_up(rt); } int query_sum(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return T[rt].sum; int m = (l + r) >> 1; int res = 0; if(L <= m) res += query_sum(L,R,l,m,T[rt].ls); if(R > m) res += query_sum(L,R,m+1,r,T[rt].rs); return res; } int query_max(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return T[rt].MAX; int m = (l + r) >> 1; int res = -1; if(L <= m) res = max(res,query_max(L,R,l,m,T[rt].ls)); if(R > m) res = max(res,query_max(L,R,m+1,r,T[rt].rs)); return res; } int solve(int op,int u,int v,int col){ int ans = 0; if(!op){ while(top[u] != top[v]){ if(dep[top[u]] < dep[top[v]]) swap(u,v); ans = max(ans,query_max(id[top[u]],id[u],1,n,root[col])); u = fa[top[u]]; } if(dep[u] > dep[v]) swap(u,v); ans = max(ans,query_max(id[u],id[v],1,n,root[col])); } else{ while(top[u] != top[v]){ if(dep[top[u]] < dep[top[v]]) swap(u,v); ans += query_sum(id[top[u]],id[u],1,n,root[col]); u = fa[top[u]]; } if(dep[u] > dep[v]) swap(u,v); ans += query_sum(id[u],id[v],1,n,root[col]); } return ans; } int main(){ //freopen("in.txt","r",stdin); init(); scanf("%d%d",&n,&q); for(int i = 1;i <= n;i++) scanf("%d%d",&w[i],&c[i]); for(int i = 1;i < n;i++){ int u,v;scanf("%d%d",&u,&v); add_edge(u,v); } dfs1(1);dfs2(1,1); for(int i = 1;i <= n;i++) update(id[i],w[i],1,n,root[c[i]]);//每次对c[i]这个颜色的树更新 while(q--){ char op[3];scanf("%s",op); if(op[0] == 'C'){ if(op[1] == 'C'){ int p,x;scanf("%d%d",&p,&x); update(id[p],0,1,n,root[c[p]]);//记得先删去原来宗教那棵树上的值 c[p] = x; update(id[p],w[p],1,n,root[c[p]]); } else{ int p,x;scanf("%d%d",&p,&x); update(id[p],x,1,n,root[c[p]]); w[p] = x; } } else{ if(op[1] == 'M'){ int l,r;scanf("%d%d",&l,&r); //cout<<id[l]<<" "<<id[r]<<endl; printf("%d\n",solve(0,l,r,c[l])); } else{ int l,r;scanf("%d%d",&l,&r); //cout<<id[l]<<" "<<id[r]<<endl; printf("%d\n",solve(1,l,r,c[l])); } } } return 0; }
相关文章推荐
- |BZOJ 3531|树链剖分|动态开点线段树|[Sdoi2014]旅行
- BZOJ 3531 (树链剖分,线段树动态开点)
- 树链剖分+动态线段树(BZOJ-3531旅行)
- [树链剖分 线段树] BZOJ 3531 [Sdoi2014]旅行
- BZOJ.3531.旅行(树链剖分 动态开点)
- bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)
- 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树
- 【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行
- [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)
- bzoj 3531(动态加点线段树,树链剖分)
- 【BZOJ3531】旅行(树链剖分,线段树)
- BZOJ[3531][Sdoi2014]旅行 树链剖分+动态开点线段树
- BZOJ-3531 旅行 树链剖分+动态开点线段树
- 【BZOJ3531】旅行,树链剖分+开点线段树
- 【bzoj3531】[Sdoi2014]旅行 动态开点的线段树
- BZOJ 3531: [Sdoi2014]旅行【树剖+动态开点线段树【听说有人写平衡树?【滑稽
- 【bzoj3531】 [SDOI2014]旅行 树链剖分+动态开点线段树
- BZOJ 3531 [Sdoi2014]旅行 树链剖分 线段树
- bzoj 3531: [Sdoi2014]旅行 树链剖分
- [bzoj3531][Sdoi2014]旅行 树链剖分