树链剖分/线段树BZOJ1036-[ZJOI2008]树的统计Count
Posted Yiyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分/线段树BZOJ1036-[ZJOI2008]树的统计Count相关的知识,希望对你有一定的参考价值。
【题目大意】
一棵树上有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本身
【思路】
我来兑现继续做ZJOI2008的flag了。裸的树链剖分,不说什么。但是!主意权值可以为负数,可以为负数!!所以初始化的时候max不是-1,而是要记得清成-INF。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 using namespace std; 9 const int MAXN=30000+50; 10 const int INF=0x7fffffff; 11 vector<int> E[MAXN]; 12 int fa[MAXN],dep[MAXN],size[MAXN],son[MAXN]; 13 int top[MAXN],pos[MAXN]; 14 int w[MAXN]; 15 int cnt=0,n; 16 int sum[MAXN<<2],maxn[MAXN<<2]; 17 char str[10]; 18 19 /*线段树部分*/ 20 void pushup(int rt) 21 { 22 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 23 maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]); 24 } 25 26 void modify(int pos,int delta,int l,int r,int rt) 27 { 28 if (l==r) 29 { 30 sum[rt]=maxn[rt]=delta; 31 return; 32 } 33 int m=(l+r)>>1; 34 if (pos<=m) modify(pos,delta,lson); 35 if (pos>m) modify(pos,delta,rson); 36 pushup(rt); 37 } 38 39 int query(int sign,int L,int R,int l,int r,int rt) 40 { 41 if (L<=l && r<=R) 42 { 43 if (sign==1) return sum[rt];else return maxn[rt]; 44 } 45 int m=(l+r)>>1; 46 if (sign==1) 47 { 48 int ret=0; 49 if (L<=m) ret+=query(sign,L,R,lson); 50 if (R>m) ret+=query(sign,L,R,rson); 51 return ret; 52 } 53 else 54 { 55 int res=-INF; 56 if (L<=m) res=max(res,query(sign,L,R,lson)); 57 if (R>m) res=max(res,query(sign,L,R,rson)); 58 return res; 59 } 60 } 61 62 /*树链剖分部分*/ 63 void addedge(int u,int v) 64 { 65 E[u].push_back(v); 66 E[v].push_back(u); 67 } 68 69 void dfs1(int u,int pre,int d) 70 { 71 fa[u]=pre; 72 dep[u]=d; 73 size[u]=1; 74 int tmpmax=0,hson=-1; 75 for (int i=0;i<E[u].size();i++) 76 { 77 int to=E[u][i]; 78 if (to==pre) continue; 79 dfs1(to,u,d+1); 80 if (size[to]>tmpmax) 81 { 82 tmpmax=size[to]; 83 hson=to; 84 } 85 size[u]+=size[to]; 86 } 87 son[u]=hson; 88 } 89 90 void dfs2(int u,int t) 91 { 92 pos[u]=++cnt; 93 top[u]=t; 94 if (son[u]==-1) return; 95 dfs2(son[u],t); 96 for (int i=0;i<E[u].size();i++) 97 if (E[u][i]!=son[u] && E[u][i]!=fa[u]) dfs2(E[u][i],E[u][i]); 98 } 99 100 int Que(int sign,int u,int v) 101 { 102 int ans; 103 if (sign==1) ans=0;else ans=-INF; 104 int f1=top[u],f2=top[v]; 105 while (f1!=f2) 106 { 107 if (dep[f1]<dep[f2]) 108 { 109 swap(f1,f2); 110 swap(u,v); 111 } 112 if (sign==1) ans+=query(1,pos[f1],pos[u],1,n,1); 113 else ans=max(ans,query(2,pos[f1],pos[u],1,n,1)); 114 u=fa[f1]; 115 f1=top[u]; 116 } 117 if (dep[u]>dep[v]) swap(u,v); 118 if (sign==1) ans+=query(1,pos[u],pos[v],1,n,1); 119 else ans=max(ans,query(2,pos[u],pos[v],1,n,1)); 120 return ans; 121 } 122 123 /*主程序部分*/ 124 void init() 125 { 126 scanf("%d",&n); 127 for (int i=0;i<n-1;i++) 128 { 129 int a,b; 130 scanf("%d%d",&a,&b); 131 addedge(a,b); 132 } 133 dfs1(1,0,1); 134 dfs2(1,1); 135 } 136 137 void get_ans() 138 { 139 for (int i=1;i<=n;i++) 140 { 141 scanf("%d",&w[i]); 142 modify(pos[i],w[i],1,n,1); 143 } 144 int q; 145 scanf("%d",&q); 146 for (int i=0;i<q;i++) 147 { 148 int u,v; 149 scanf("%s%d%d",str,&u,&v); 150 if (str[0]==‘C‘) modify(pos[u],v,1,n,1); 151 if (str[0]==‘Q‘ && str[1]==‘S‘) cout<<Que(1,u,v)<<endl; 152 if (str[0]==‘Q‘ && str[1]==‘M‘) cout<<Que(2,u,v)<<endl; 153 } 154 } 155 156 int main() 157 { 158 init(); 159 get_ans(); 160 return 0; 161 }
以上是关于树链剖分/线段树BZOJ1036-[ZJOI2008]树的统计Count的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1036: [ZJOI2008]树的统计Count(树链剖分+线段树维护)
树链剖分/线段树BZOJ1036-[ZJOI2008]树的统计Count