萌新刚学树剖,求救

P3384 【模板】重链剖分/树链剖分

@[Fractures](/space/show?uid=78791) dfs1里是不是size忘赋初值1了qwq
by Ynoi @ 2019-08-03 08:38:00


你应该先dfs再build建树
by ZYF_B @ 2019-08-03 08:38:39


而且build中的a[l]应该改成a[rnk[l]]
by ZYF_B @ 2019-08-03 08:43:42


楼上大佬说的都对
by Frozencode @ 2019-08-03 08:43:47


@[树链剖分](/space/show?uid=124721) 改了之后为什么输出出问题了 ```cpp #include<cstdio> #include<iomanip> #define ll long long using std::max; using std::swap; const int MAXN=100001; int n,m,r,p; ll a[MAXN],tag[MAXN<<2],ans[MAXN<<2]; ll to[MAXN],next[MAXN],head[MAXN]; inline void add(int a,int b){ static int ccnt=0; ccnt++; next[ccnt]=head[a]; head[a]=ccnt; to[ccnt]=b; } ll father[MAXN],son[MAXN],top[MAXN],depth[MAXN],size[MAXN],tid[MAXN],rnk[MAXN]; void dfs1(int u,int fa){ father[u]=fa; depth[u]=depth[fa]+1; int big=-2333; size[u]=1; for(int i=head[u];i;i=next[i]){ int v=to[i]; if(v==fa)continue; dfs1(v,u); size[u]+=size[v]; if(size[v]>big){ son[u]=v; big=size[v]; } } } int ccnt; void dfs2(int u,int t){ ccnt++; top[u]=t; tid[u]=ccnt; rnk[ccnt]=u; if(son[u])dfs2(son[u],t); for(int i=head[u];i;i=next[i]){ int v=to[i]; if(v==father[u])continue; if(v==son[u])continue; dfs2(v,v); } } inline ll ls(ll x){ return x<<1; } inline ll rs(ll x){ return x<<1|1; } inline void push_up(ll x){ ans[x]=ans[ls(x)]+ans[rs(x)]; } void build(ll x,ll l,ll r){ if(l==r){ ans[x]=a[l]; return; } ll mid=(l+r)>>1; build(ls(x),l,mid); build(rs(x),mid+1,r); push_up(x); } inline void f(ll x,ll l,ll r,ll k){ tag[x]+=k; ans[x]+=(r-l+1)*k; } inline void push_down(ll x,ll l,ll r){ ll mid=(l+r)>>1; f(ls(x),l,mid,tag[x]); f(rs(x),mid+1,r,tag[x]); tag[x]=0; } ll query(ll ask_l,ll ask_r,ll l,ll r,ll x){ ll res=0; if(ask_l<=l&&r<=ask_r){ return ans[x]; } ll mid=(l+r)>>1; push_down(x,l,r); if(ask_l<=mid)res+=query(ask_l,ask_r,l,mid,ls(x)); if(ask_r>mid)res+=query(ask_l,ask_r,mid+1,r,rs(x)); return res; } void update(ll now_l,ll now_r,ll l,ll r,ll x,ll k){ if(now_l<=l&&r<=now_r){ f(x,l,r,k); return; } ll mid=(l+r)>>1; push_down(x,l,r); if(now_l<=mid)update(now_l,now_r,l,mid,ls(x),k); if(now_l>mid)update(now_l,now_r,mid+1,r,rs(x),k); push_up(x); } inline int getn(int x,int y){ ll ans=0; while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]])swap(x,y); ans+=query(tid[top[x]],tid[x],1,n,1)%p; ans%=p; x=father[top[x]]; } if(depth[x]<depth[y]){ swap(x,y); } ans+=query(tid[y],tid[x],1,n,1)%p; return ans%p; } inline void put(int x,int y,ll z){ while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]])swap(x,y); update(tid[top[x]],tid[x],1,n,1,z); x=father[top[x]]; } if(depth[x]<depth[y]){ swap(x,y); } update(tid[y],tid[x],1,n,1,z); } int main(){ scanf("%d%d%d%d",&n,&m,&r,&p); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<n;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs1(r,0); dfs2(r,r); build(1,1,n); for(int i=1;i<=m;i++){ int k; scanf("%d",&k); if(k==1){ int x,y,z; scanf("%d%d%d",&x,&y,&z); put(x,y,z); } if(k==2){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",getn(x,y)); } if(k==3){ int x,z; scanf("%d%d",&x,&z); update(tid[x],tid[x]+size[x]-1,1,n,1,z); } if(k==4){ int x; scanf("%d",&x); printf("%lld\n",query(tid[x],tid[x]+size[x]-1,1,n,1)); } } return 0; } ``` 输入: ``` 5 5 2 24 7 3 7 8 0 1 2 1 5 3 1 4 1 3 4 2 3 2 2 4 5 1 5 1 3 2 1 3 ``` 应该输出: ``` 2 21 ``` 实际输出: ``` 2 18 ```
by Fractures @ 2019-08-03 08:45:07


@[Fractures](/space/show?uid=78791) emm,看看ZYF_B dalao说的吧qwq
by Ynoi @ 2019-08-03 08:46:07


@[ZYF_B](/space/show?uid=71514) 我没看见呢……谢谢大佬
by Fractures @ 2019-08-03 08:46:10


@[树链剖分](/space/show?uid=124721) qaq
by Fractures @ 2019-08-03 08:46:30


你把build中a[l]换成a[rnk[l]]就对了
by ZYF_B @ 2019-08-03 08:47:40


线段树中的值都是重新编号过后的,刚学确实容易弄混
by ZYF_B @ 2019-08-03 08:50:22


| 下一页