码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-09-15 19:26:59      阅读:214      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!