[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分
Posted SkyLYnf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分相关的知识,希望对你有一定的参考价值。
Problem 树的统计
题目大意
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
So Lazy No Solution
裸的树链剖分,题解一搜一大把。就连这个都炸了几次。我太菜了。。。
AC Code
#include <iostream> #include <cstdio> #include <cstring> #include <climits> #define lc now<<1 using namespace std; struct SGTree{ int val,sum,mx; }tr[120010]; struct Node{ int to,next; }a[60010]; int tot=0,dtot=0,x,n,m,h[30010],dep[30010],up[30010],size[30010]; int dfn[30010],rk[30010],fa[30010],val[30010],son[30010]; char tsk[10]; int dfs_sz(int now,int father,int depth){ dep[now]=depth; fa[now]=father; int maxs=0,maxn=0; for(int i=h[now];~i;i=a[i].next) if(a[i].to!=father) size[now]+=dfs_sz(a[i].to,now,depth+1), maxs=max(size[a[i].to],maxs), maxn=(maxs==size[a[i].to])?a[i].to:maxn; son[now]=(maxn==0)?-1:maxn; size[now]++; return size[now]; } void dfs_son(int now,int upest){ dfn[now]=++dtot; rk[dtot]=now; up[now]=upest; if(son[now]==-1)return; dfs_son(son[now],upest); for(int i=h[now];~i;i=a[i].next) if(a[i].to!=fa[now]&&a[i].to!=son[now]) dfs_son(a[i].to,a[i].to); } void add(int u,int v){ a[++tot].to=v;a[tot].next=h[u];h[u]=tot; a[++tot].to=u;a[tot].next=h[v];h[v]=tot; } void build(int l,int r,int now){ if(l==r){ tr[now].mx=tr[now].val=tr[now].sum=val[rk[l]]; return; } int mid=(l+r)>>1; tr[lc].mx=-INT_MAX,tr[(lc)+1].mx=-INT_MAX; build(l,mid,lc); build(mid+1,r,(lc)+1); tr[now].mx=max(tr[lc].mx,tr[(lc)+1].mx); tr[now].sum=tr[lc].sum+tr[(lc)+1].sum; } int sgt_max(int s,int t,int l,int r,int now){ if(l==s&&r==t)return tr[now].mx; int mid=(l+r)>>1; if(t<=mid)return sgt_max(s,t,l,mid,lc); else if(mid<s)return sgt_max(s,t,mid+1,r,(lc)+1); else return max(sgt_max(s,mid,l,mid,lc),sgt_max(mid+1,t,mid+1,r,(lc)+1)); } int sgt_sum(int s,int t,int l,int r,int now){ if(l==s&&r==t)return tr[now].sum; int mid=(l+r)>>1; if(t<=mid)return sgt_sum(s,t,l,mid,lc); else if(mid<s)return sgt_sum(s,t,mid+1,r,(lc)+1); else return sgt_sum(s,mid,l,mid,lc)+sgt_sum(mid+1,t,mid+1,r,(lc)+1); } int query_max(int s,int t){ int u=up[s],v=up[t],ret=-INT_MAX; while(u!=v){ if(dep[u]<dep[v])swap(u,v),swap(s,t); ret=max(ret,sgt_max(dfn[u],dfn[s],1,dtot,1)); s=fa[u]; u=up[s]; } if(dep[s]>dep[t])swap(s,t); ret=max(ret,sgt_max(dfn[s],dfn[t],1,dtot,1)); return ret; } int query_sum(int s,int t){ int u=up[s],v=up[t],ret=0; while(u!=v){ if(dep[u]<dep[v])swap(u,v),swap(s,t); ret+=sgt_sum(dfn[u],dfn[s],1,dtot,1); s=fa[u]; u=up[s]; } if(dep[s]>dep[t])swap(s,t); ret+=sgt_sum(dfn[s],dfn[t],1,dtot,1); return ret; } void change(int u,int x,int l,int r,int now){ if(l==r&&l==u){ tr[now].val=tr[now].mx=tr[now].sum=x; return; } int mid=(l+r)>>1; if(u<=mid)change(u,x,l,mid,lc); else change(u,x,mid+1,r,(lc)+1); tr[now].mx=max(tr[lc].mx,tr[(lc)+1].mx); tr[now].sum=tr[lc].sum+tr[(lc)+1].sum;} int main(){ // freopen("bzoj1036.in","r",stdin); memset(h,-1,sizeof(h)); int u,v; scanf("%d",&n); for(int i=1;i<n;i++) scanf("%d%d",&u,&v), add(u,v); dfs_sz(1,0,0); dfs_son(1,1); for(int i=1;i<=n;i++) scanf("%d",&val[i]); build(1,dtot,1); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%s",tsk); if(tsk[0]==‘Q‘&&tsk[1]==‘M‘) scanf("%d%d",&u,&v), printf("%d\n",query_max(u,v)); else if(tsk[0]==‘Q‘&&tsk[1]==‘S‘) scanf("%d%d",&u,&v), printf("%d\n",query_sum(u,v)); else if(tsk[0]==‘C‘) scanf("%d%d",&u,&x), change(dfn[u],x,1,dtot,1); } }
以上是关于[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)
BZOJ 1036: [ZJOI2008]树的统计Count
bzoj 1036: [ZJOI2008]树的统计Count
BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]