[BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
来源:互联网 发布:阿里旺旺软件下载 编辑:程序博客网 时间:2024/05/16 15:22
题目描述
传送门
题解
树链剖分模板题。
代码
// BZOJ 1036#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int max_n=3e4+5;const int max_e=max_n*4;const int max_N=max_n*4+5;const int mininf=-2100000000;int n,x,y,N,q,u,t,ans,f1,f2;//w[i]表示点i的权值,size[i]表示以i为根的子树的结点个数,h[i]表示点i的深度,father[i]表示点i的父亲,son[i]表示点i的重儿子 int w[max_n],size[max_n],h[max_n],father[max_n],son[max_n];//top[i]表示点i所在的链的最头上的点,num[i]表示点i在线段树数组中对应的编号,tree[i]表示在线段树数组中编号为i的点在树中对应的点的编号 int top[max_n],num[max_n],tree[max_n];int point[max_n],next[max_e],v[max_e],tot;char order[10];int sum[max_N],maxn[max_N];inline void add(int x,int y){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;}inline void dfs_1(int x,int fa,int dep){ size[x]=1; h[x]=dep; father[x]=fa; int maxson=0; for (int i=point[x];i;i=next[i]) if (v[i]!=fa){ dfs_1(v[i],x,dep+1); size[x]+=size[v[i]]; if (size[v[i]]>maxson){ maxson=size[v[i]]; son[x]=v[i]; } }}inline void dfs_2(int x,int fa){ if (son[fa]!=x) top[x]=x; else top[x]=top[fa]; num[x]=++N; if (son[x]) dfs_2(son[x],x); for (int i=point[x];i;i=next[i]) if (v[i]!=fa&&v[i]!=son[x]) dfs_2(v[i],x);}inline void update_sum(int now){ sum[now]=sum[now<<1]+sum[now<<1|1];}inline void update_max(int now){ maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);}inline void build_sum(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ sum[now]=w[tree[l]]; return; } build_sum(now<<1,l,mid); build_sum(now<<1|1,mid+1,r); update_sum(now);}inline void build_max(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ maxn[now]=w[tree[l]]; return; } build_max(now<<1,l,mid); build_max(now<<1|1,mid+1,r); update_max(now);}inline void point_change_sum(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (l==r){ sum[now]=v; return; } if (x<=mid) point_change_sum(now<<1,l,mid,x,v); else point_change_sum(now<<1|1,mid+1,r,x,v); update_sum(now);}inline void point_change_max(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (l==r){ maxn[now]=v; return; } if (x<=mid) point_change_max(now<<1,l,mid,x,v); else point_change_max(now<<1|1,mid+1,r,x,v); update_max(now);}inline int query_sum(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return sum[now]; if (lrange<=mid) ans+=query_sum(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) ans+=query_sum(now<<1|1,mid+1,r,lrange,rrange); return ans;}inline int query_max(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=mininf; if (lrange<=l&&r<=rrange) return maxn[now]; if (lrange<=mid) ans=max(ans,query_max(now<<1,l,mid,lrange,rrange)); if (mid+1<=rrange) ans=max(ans,query_max(now<<1|1,mid+1,r,lrange,rrange)); return ans;}int main(){ scanf("%d",&n); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } for (int i=1;i<=n;++i) scanf("%d",&w[i]); //预处理size,h,father,son的值 dfs_1(1,0,1); //预处理top,num,tree的值 dfs_2(1,0); for (int i=1;i<=n;++i) tree[num[i]]=i; build_sum(1,1,N); build_max(1,1,N); scanf("%d",&q); for (int i=1;i<=q;++i){ scanf("%s",order); while (strlen(order)<4) scanf("%s",order); scanf("%d%d",&u,&t); if (order[0]=='C'){ point_change_sum(1,1,N,num[u],t); point_change_max(1,1,N,num[u],t); } else{ if (order[1]=='S'){ ans=0; f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans+=query_sum(1,1,N,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); ans+=query_sum(1,1,N,num[u],num[t]); printf("%d\n",ans); } else{ ans=mininf; f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans=max(ans,query_max(1,1,N,num[f1],num[u])); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); ans=max(ans,query_max(1,1,N,num[u],num[t])); printf("%d\n",ans); } } }}
手写栈
#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int max_n=3e4+5;const int max_e=max_n*4;const int max_N=max_n*4+5;const int mininf=-2100000000;int n,x,y,N,q,u,t,ans,f1,f2;int w[max_n],size[max_n],h[max_n],father[max_n],son[max_n];int top[max_n],num[max_n],tree[max_n];int strack[max_n],cur[max_n],use[max_n];int point[max_n],nxt[max_e],v[max_e],tot;char order[10];int sum[max_N],maxn[max_N];inline void add(int x,int y){ ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}inline void dfs_1(){ int temp=0; strack[++temp]=1; size[1]=1; h[1]=1; for (int i=1;i<=n;++i) cur[i]=point[i]; while (temp) { int x=strack[temp]; if (v[cur[x]]==father[x]) cur[x]=nxt[cur[x]]; if (!cur[x]) { temp--; if (father[x]) { size[father[x]]+=size[x]; if (size[x]>size[son[father[x]]]) son[father[x]]=x; } continue; } int vt=v[cur[x]]; strack[++temp]=vt; size[vt]=1; h[vt]=h[x]+1; father[vt]=x; cur[x]=nxt[cur[x]]; }}inline void dfs_2(){ int temp=0; strack[++temp]=1; num[1]=++N; top[1]=1; for (int i=1;i<=n;++i) cur[i]=point[i]; while (temp) { int x=strack[temp]; if (!use[x]) { use[x]=1; int vt=son[x]; if (vt) { strack[++temp]=vt; top[vt]=top[x]; num[vt]=++N; } continue; } while (cur[x]&&(v[cur[x]]==father[x]||v[cur[x]]==son[x])) cur[x]=nxt[cur[x]]; if (!cur[x]) { temp--; continue; } else { int vt=v[cur[x]]; strack[++temp]=vt; top[vt]=vt; num[vt]=++N; cur[x]=nxt[cur[x]]; } }}inline void update_sum(int now){ sum[now]=sum[now<<1]+sum[now<<1|1];}inline void update_max(int now){ maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);}inline void build_sum(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ sum[now]=w[tree[l]]; return; } build_sum(now<<1,l,mid); build_sum(now<<1|1,mid+1,r); update_sum(now);}inline void build_max(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ maxn[now]=w[tree[l]]; return; } build_max(now<<1,l,mid); build_max(now<<1|1,mid+1,r); update_max(now);}inline void point_change_sum(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (l==r){ sum[now]=v; return; } if (x<=mid) point_change_sum(now<<1,l,mid,x,v); else point_change_sum(now<<1|1,mid+1,r,x,v); update_sum(now);}inline void point_change_max(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (l==r){ maxn[now]=v; return; } if (x<=mid) point_change_max(now<<1,l,mid,x,v); else point_change_max(now<<1|1,mid+1,r,x,v); update_max(now);}inline int query_sum(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return sum[now]; if (lrange<=mid) ans+=query_sum(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) ans+=query_sum(now<<1|1,mid+1,r,lrange,rrange); return ans;}inline int query_max(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=mininf; if (lrange<=l&&r<=rrange) return maxn[now]; if (lrange<=mid) ans=max(ans,query_max(now<<1,l,mid,lrange,rrange)); if (mid+1<=rrange) ans=max(ans,query_max(now<<1|1,mid+1,r,lrange,rrange)); return ans;}int main(){ scanf("%d",&n); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } for (int i=1;i<=n;++i) scanf("%d",&w[i]); dfs_1(); dfs_2(); for (int i=1;i<=n;++i) tree[num[i]]=i; build_sum(1,1,N); build_max(1,1,N); scanf("%d",&q); for (int i=1;i<=q;++i){ scanf("%s",order); scanf("%d%d",&u,&t); if (order[0]=='C'){ point_change_sum(1,1,N,num[u],t); point_change_max(1,1,N,num[u],t); } else{ if (order[1]=='S'){ ans=0; f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans+=query_sum(1,1,N,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); ans+=query_sum(1,1,N,num[u],num[t]); printf("%d\n",ans); } else{ ans=mininf; f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans=max(ans,query_max(1,1,N,num[f1],num[u])); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); ans=max(ans,query_max(1,1,N,num[u],num[t])); printf("%d\n",ans); } } }}
总结
①线段树要开4n,不要开2n
②线段树的操作可以合并
0 0
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
- 【bzoj1036】【树链剖分】【ZJOI2008】树的统计Count
- 【BZOJ1036】【ZJOI2008】【树的统计count】【树链剖分】
- BZOJ1036: [ZJOI2008]树的统计Count (树链剖分)
- bzoj1036: [ZJOI2008]树的统计Count - 树链剖分
- 【树链剖分】[BZOJ1036][ZJOI2008]树的统计Count
- [树链剖分] BZOJ1036: [ZJOI2008]树的统计Count
- [bzoj1036][ZJOI2008]树的统计Count 树链剖分
- 【bzoj1036】【树链剖分】 [ZJOI2008]树的统计Count
- BZOJ1036 [ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- 树链剖分基础模板(BZOJ1036[ZJOI2008]树的统计Count)
- bzoj1036: [ZJOI2008]树的统计Count(树链剖分)
- [bzoj1036]:[ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- [Bzoj1036][ZJOI2008]树的统计Count
- hdu2553 N皇后问题(回溯dfs)
- less
- hadoop搭建完毕后启动hadoop弹出ssh警告提示的解决办法
- IOS开发之UIView总结
- uva10271 经典DP
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- python入门
- IOS 将数组转化成NSData数据进行保存
- ser2net和socat
- ios中的动画
- 贝叶斯和频率的哲思
- JAVA开发环境配置
- VS2010中如何添加“依赖”、“库目录”、“包含目录”
- [HDU 2896] - 病毒侵袭 ac 自动机