首页 > 代码库 > 【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count

【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count

很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了。

  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         else168           {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