标签:style blog color io ar strong for div sp
很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 #define lson rt<<1,l,m 6 #define rson rt<<1|1,m+1,r 7 #define maxn 60000 8 int n,m,u,v; 9 int V[maxn],Next[maxn],First[maxn]; 10 int Val[maxn]; 11 int fa[maxn],dep[maxn],son[maxn],siz[maxn],top[maxn],Num[maxn],tot,en; 12 int maxv[maxn<<2],sumv[maxn<<2]; 13 bool vis[maxn]; 14 char s[7]; 15 inline void AddEdge(int UU,int VV) 16 { 17 V[++en]=VV; 18 Next[en]=First[UU]; 19 First[UU]=en; 20 } 21 int query_sum(int ql,int qr,int rt,int l,int r) 22 { 23 if(ql<=l&&r<=qr) 24 return sumv[rt]; 25 int m=l+r>>1,ans=0; 26 if(ql<=m) 27 ans+=query_sum(ql,qr,lson); 28 if(m<qr) 29 ans+=query_sum(ql,qr,rson); 30 return ans; 31 } 32 int query_max(int ql,int qr,int rt,int l,int r) 33 { 34 if(ql<=l&&r<=qr) 35 return maxv[rt]; 36 int m=l+r>>1,ans=-2147483647; 37 if(ql<=m) 38 ans=max(ans,query_max(ql,qr,lson)); 39 if(m<qr) 40 ans=max(ans,query_max(ql,qr,rson)); 41 return ans; 42 } 43 void update(int p,int v,int rt,int l,int r) 44 { 45 int m=l+r>>1; 46 if(l==r) 47 { 48 maxv[rt]=sumv[rt]=v; 49 return; 50 } 51 if(p<=m) 52 update(p,v,lson); 53 else 54 update(p,v,rson); 55 sumv[rt]=sumv[rt<<1]+sumv[(rt<<1)+1]; 56 maxv[rt]=max(maxv[rt<<1],maxv[(rt<<1)+1]); 57 } 58 inline void Change(int p,int v) 59 { 60 update(p,v,1,1,n); 61 } 62 inline int Query_sum(int u,int v) 63 { 64 int f1=top[u],f2=top[v],res=0; 65 while(f1!=f2) 66 { 67 if(dep[f1]<dep[f2]) 68 { 69 swap(u,v); 70 swap(f1,f2); 71 } 72 res+=query_sum(Num[f1],Num[u],1,1,n); 73 u=fa[f1]; 74 f1=top[u]; 75 } 76 if(dep[u]>dep[v]) 77 swap(u,v); 78 return res+query_sum(Num[u],Num[v],1,1,n); 79 } 80 inline int Query_max(int u,int v) 81 { 82 int f1=top[u],f2=top[v],res=-2147483647; 83 while(f1!=f2) 84 { 85 if(dep[f1]<dep[f2]) 86 { 87 swap(u,v); 88 swap(f1,f2); 89 } 90 res=max(res,query_max(Num[f1],Num[u],1,1,n)); 91 u=fa[f1]; 92 f1=top[u]; 93 } 94 if(dep[u]>dep[v]) 95 swap(u,v); 96 return max(res,query_max(Num[u],Num[v],1,1,n)); 97 } 98 void dfs1(int cur,int father,int depth) 99 { 100 fa[cur]=father; 101 dep[cur]=depth; 102 siz[cur]=1; 103 for(int i=First[cur];i;i=Next[i]) 104 if(!vis[V[i]]) 105 { 106 vis[V[i]]=true; 107 dfs1(V[i],cur,depth+1); 108 siz[cur]+=siz[V[i]]; 109 if(siz[V[i]]>siz[son[cur]]) 110 son[cur]=V[i]; 111 vis[V[i]]=false; 112 } 113 } 114 void dfs2(int cur) 115 { 116 if(son[cur]&&!vis[son[cur]]) 117 { 118 vis[son[cur]]=true; 119 top[son[cur]]=top[cur]; 120 Num[son[cur]]=++tot; 121 Change(tot,Val[son[cur]]); 122 dfs2(son[cur]); 123 vis[son[cur]]=false; 124 } 125 for(int i=First[cur];i;i=Next[i]) 126 if(son[cur]!=V[i]&&!vis[V[i]]) 127 { 128 vis[V[i]]=true; 129 top[V[i]]=V[i]; 130 Num[V[i]]=++tot; 131 Change(tot,Val[V[i]]); 132 dfs2(V[i]); 133 vis[V[i]]=false; 134 } 135 } 136 int main() 137 { 138 scanf("%d",&n); 139 for(int i=1;i<n;i++) 140 { 141 scanf("%d%d",&u,&v); 142 AddEdge(u,v); 143 AddEdge(v,u); 144 } 145 for(int i=1;i<=n;i++) 146 scanf("%d",&Val[i]); 147 top[1]=1; 148 Num[1]=++tot; 149 Change(tot,Val[1]); 150 vis[1]=true; 151 dfs1(1,0,1); 152 dfs2(1); 153 scanf("%d",&m); 154 for(int i=1;i<=m;i++) 155 { 156 scanf("%s",s); 157 if(s[1]==‘H‘) 158 { 159 scanf("%d%d",&u,&v); 160 Change(Num[u],v); 161 } 162 else if(s[1]==‘M‘) 163 { 164 scanf("%d%d",&u,&v); 165 printf("%d\n",Query_max(u,v)); 166 } 167 else 168 { 169 scanf("%d%d",&u,&v); 170 printf("%d\n",Query_sum(u,v)); 171 } 172 } 173 return 0; 174 }
学了个块状树,好写不少,而且常数较小,比链剖慢不了多少。
在dfs时分块,只要当前块满了sqrt(n),就分新的一块。
对每个点,维护从这个点到该块的根(top)的路径上的答案。
更新的时候,只会对 该点 在该块内的子树 造成影响。
询问时,暴力LCA。
这样更新和询问都是O(sqrt(n))的。
Orz zky。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 struct Graph 6 { 7 int v[60001],first[60001],next[60001],en; 8 void AddEdge(const int &a,const int &b) 9 {v[++en]=b;next[en]=first[a];first[a]=en;} 10 }; 11 Graph G[2]; 12 int fa[30001],dep[30001],top[30001],siz[30001],sz; 13 int maxv[30001],sumv[30001],w[30001]; 14 int n,x,y,q; 15 char op[10]; 16 void makeblock(int cur) 17 { 18 for(int i=G[0].first[cur];i;i=G[0].next[i]) 19 if(G[0].v[i]!=fa[cur]) 20 { 21 dep[G[0].v[i]]=dep[cur]+1; 22 fa[G[0].v[i]]=cur; 23 if(siz[top[cur]]<sz) 24 { 25 siz[top[cur]]++; 26 top[G[0].v[i]]=top[cur]; 27 G[1].AddEdge(cur,G[0].v[i]); 28 } 29 makeblock(G[0].v[i]); 30 } 31 } 32 void dfs(int cur,int Sumnow,int Maxnow) 33 { 34 maxv[cur]=Maxnow; 35 sumv[cur]=Sumnow; 36 for(int i=G[1].first[cur];i;i=G[1].next[i]) 37 dfs(G[1].v[i],Sumnow+w[G[1].v[i]],max(Maxnow,w[G[1].v[i]])); 38 } 39 inline void update(int p,int val) 40 { 41 w[p]=val; 42 if(p==top[p]) dfs(p,val,val); 43 else dfs(p,val+sumv[fa[p]],max(val,maxv[fa[p]])); 44 } 45 inline int Query_max(int u,int v) 46 { 47 int res=-2147483647; 48 while(u!=v) 49 { 50 if(top[u]==top[v]) 51 { 52 if(dep[u]<dep[v]) swap(u,v); 53 res=max(res,w[u]); 54 u=fa[u]; 55 } 56 else 57 { 58 if(dep[top[u]]<dep[top[v]]) swap(u,v); 59 res=max(res,maxv[u]); 60 u=fa[top[u]]; 61 } 62 } 63 return max(res,w[u]); 64 } 65 inline int Query_sum(int u,int v) 66 { 67 int res=0; 68 while(u!=v) 69 { 70 if(top[u]==top[v]) 71 { 72 if(dep[u]<dep[v]) 73 swap(u,v); 74 res+=w[u]; 75 u=fa[u]; 76 } 77 else 78 { 79 if(dep[top[u]]<dep[top[v]]) 80 swap(u,v); 81 res+=sumv[u]; 82 u=fa[top[u]]; 83 } 84 } 85 return res+w[u]; 86 } 87 int main() 88 { 89 scanf("%d",&n); 90 for(int i=1;i<n;i++) 91 { 92 scanf("%d%d",&x,&y); 93 G[0].AddEdge(x,y); 94 G[0].AddEdge(y,x); 95 } 96 sz=sqrt(n); 97 for(int i=1;i<=n;i++) 98 { 99 scanf("%d",&w[i]); 100 top[i]=i; 101 siz[i]=1; 102 } 103 makeblock(1); 104 for(int i=1;i<=n;i++) 105 if(top[i]==i) dfs(i,w[i],w[i]); 106 scanf("%d",&q); 107 for(int i=1;i<=q;i++) 108 { 109 scanf("%s%d%d",op,&x,&y); 110 if(op[1]==‘M‘) printf("%d\n",Query_max(x,y)); 111 else if(op[1]==‘H‘) update(x,y); 112 else printf("%d\n",Query_sum(x,y)); 113 } 114 return 0; 115 }
【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count
标签:style blog color io ar strong for div sp
原文地址:http://www.cnblogs.com/autsky-jadek/p/3973378.html