BZOJ 3531(树链剖分+线段树)
Problem 旅行 (BZOJ 3531)
题目大意
给定一颗树,树上的每个点有两个权值(x,y)。
要求维护4种操作:
操作1:更改某个点的权值x。
操作2:更改某个点的权值y。
操作3:求a-->b路径上所有x属性与a,b相同的点y属性的和。
操作4:求a-->b路径上所有x属性与a,b相同的点y属性的最大值。
N,Q ,x <= 10^5 , y <= 10^4
解题分析
由于x属性的范围较大,无法直接统计。
考虑每次修改为单点修改,询问时只对相同x属性的询问。
因此,对于每个x属性开一棵线段树,询问时直接在相对应的线段树内查询。
开这么多棵线段树的话,就要动态开点,某个点的左右儿子的编号不是当前点编号的2倍或2倍加1。
参考程序
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 #define N 10000008 8 #define V 100008 9 #define E 200008 10 #define lson l,m,ls[rt] 11 #define rson m+1,r,rs[rt] 12 13 int n,Q,cnt; 14 int size[V],dep[V],fa[V],son[V],w[V],top[V],rk[V],root[V]; 15 int a[V],c[V]; 16 17 struct line{ 18 int u,v,nt; 19 }eg[E]; 20 int lt[V],sum; 21 22 void adt(int u,int v){ 23 eg[++sum].u=u; eg[sum].v=v; eg[sum].nt=lt[u]; lt[u]=sum; 24 } 25 void add(int u,int v){ 26 adt(u,v); adt(v,u); 27 } 28 29 struct segment_tree{ 30 int sum[N],mx[N],ls[N],rs[N]; 31 void pushup(int rt){ 32 sum[rt]=sum[ls[rt]]+sum[rs[rt]]; 33 mx[rt]=max(mx[ls[rt]],mx[rs[rt]]); 34 } 35 void update(int x,int val,int l,int r,int &rt){ //============ 这个 & 符号用得还是蛮精髓的 ==================== 36 if (rt==0) rt=++cnt; 37 if (l==r){ 38 sum[rt]=val; 39 mx[rt]=val; 40 return; 41 } 42 int m=(l+r)/2; 43 if (x <= m) update(x,val,lson); 44 if (m < x) update(x,val,rson); 45 pushup(rt); 46 } 47 int query_sum(int L,int R,int l,int r,int rt){ 48 if (L<=l && r<=R){ 49 return sum[rt]; 50 } 51 int m=(l+r)/2; 52 int res=0; 53 if (L <= m) res+=query_sum(L,R,lson); 54 if (m < R) res+=query_sum(L,R,rson); 55 return res; 56 } 57 int query_max(int L,int R,int l,int r,int rt){ 58 if (L<=l && r<=R){ 59 return mx[rt]; 60 } 61 int m=(l+r)/2; 62 int res=0; 63 if (L <= m) res=max(res,query_max(L,R,lson)); 64 if (m < R) res=max(res,query_max(L,R,rson)); 65 return res; 66 } 67 }T; 68 69 void dfs_1(int u){ 70 dep[u]=dep[fa[u]]+1; size[u]=1; son[u]=0; 71 for (int i=lt[u];i;i=eg[i].nt){ 72 int v=eg[i].v; 73 if (v==fa[u]) continue; 74 fa[v]=u; 75 dfs_1(v); 76 size[u]+=size[v]; 77 if (size[v]>size[son[u]]) son[u]=v; 78 } 79 } 80 void dfs_2(int u,int tp){ 81 top[u]=tp; w[u]=++cnt; rk[cnt]=u; 82 if (son[u]) dfs_2(son[u],tp); 83 for (int i=lt[u];i;i=eg[i].nt){ 84 int v=eg[i].v; 85 if (v==fa[u] || v==son[u]) continue; 86 dfs_2(v,v); 87 } 88 } 89 void solve_sum(int x,int y){ 90 int res=0,cl=c[x]; 91 while (top[x]!=top[y]){ 92 if (dep[top[x]]<dep[top[y]]) swap(x,y); 93 res+=T.query_sum(w[top[x]],w[x],1,n,root[cl]); 94 x=fa[top[x]]; 95 } 96 if (dep[x]>dep[y]) swap(x,y); 97 res+=T.query_sum(w[x],w[y],1,n,root[cl]); 98 printf("%d\n",res); 99 } 100 void solve_max(int x,int y){ 101 int res=0,cl=c[x]; 102 while (top[x]!=top[y]){ 103 if (dep[top[x]]<dep[top[y]]) swap(x,y); 104 res=max(res,T.query_max(w[top[x]],w[x],1,n,root[cl])); 105 x=fa[top[x]]; 106 } 107 if (dep[x]>dep[y]) swap(x,y); 108 res=max(res,T.query_max(w[x],w[y],1,n,root[cl])); 109 printf("%d\n",res); 110 } 111 112 int main(){ 113 memset(lt,0,sizeof(lt)); sum=1; 114 scanf("%d %d",&n,&Q); 115 for (int i=1;i<=n;i++) scanf("%d %d",&a[i],&c[i]); 116 for (int i=1;i<n;i++){ 117 int u,v; 118 scanf("%d %d",&u,&v); 119 add(u,v); 120 } 121 dfs_1(1); 122 dfs_2(1,1); 123 cnt=0; 124 for (int i=1;i<=n;i++) T.update(w[i],a[i],1,n,root[c[i]]); 125 while (Q--){ 126 char x[5]; 127 int y,z; 128 scanf("%s%d%d",x,&y,&z); 129 if (strcmp(x,"CC")==0){ 130 T.update(w[y],0,1,n,root[c[y]]); 131 c[y]=z; 132 T.update(w[y],a[y],1,n,root[c[y]]); 133 } 134 if (strcmp(x,"CW")==0){ 135 a[y]=z; // ====================== debug ============// 136 T.update(w[y],z,1,n,root[c[y]]); 137 } 138 if (strcmp(x,"QS")==0){ 139 solve_sum(y,z); 140 } 141 if (strcmp(x,"QM")==0){ 142 solve_max(y,z); 143 } 144 } 145 }