萌新刚学OI,树链剖分莫名写炸求救

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

或许我应该@[树链剖分](/space/show?uid=124721) ?
by 引领天下 @ 2019-07-13 16:49:26


@[引领天下](/space/show?uid=39863) 你为什么`query`和`chge`为什么要写`tree.ask(r,...)`之类的东西啊……
by F1aMiR3 @ 2019-07-13 17:01:10


~~同问。~~
by nosta @ 2019-07-13 17:02:54


~~宁的线段树似乎是建在点的原编号上而不是dfs序上的~~
by kma_093 @ 2019-07-13 17:04:46


还有宁的dfs2是不是手癌了 ``` if (to[i]==fa[i]||to[i]==son[i])continue; ``` 应该是 ``` if (to[i]==fa[x]||to[i]==son[x])continue; ```
by kma_093 @ 2019-07-13 17:14:42


``` #include <bits/stdc++.h> #define int long long using namespace std; const int N=100005; #define ll long long int dep[N],siz[N],fa[N],z[N],to[N<<1],beg[N<<1],nxt[N<<1],top[N<<2],bian,son[N<<1],id[N<<1],tot,n,m,r,mod,num[N]; struct Tree{ ll ans[N<<2],tag[N<<2],a[N]; inline ll lson(ll p){return p<<1;} inline ll rson(ll p){return (p<<1)|1;} inline void push_up(ll p){ans[p]=(ans[lson(p)]+ans[rson(p)])%mod;} inline void build(ll p,ll l,ll r){ if (l==r){ans[p]=a[num[l]];return ;} ll mid=(l+r)>>1; build(lson(p),l,mid); build(rson(p),mid+1,r); push_up(p); tag[p]=0; } inline void lazy_tag(ll p,ll l,ll r,ll k){ans[p]=(ans[p]+(r-l+1)*k)%mod,tag[p]=(tag[p]+k)%mod;} inline void push_down(ll p,ll l,ll r){ ll mid=(l+r)>>1; lazy_tag(lson(p),l,mid,tag[p]); lazy_tag(rson(p),mid+1,r,tag[p]); tag[p]=0; } inline void change(ll p,ll nl,ll nr,ll l,ll r,ll k){//nl,nr->changing l,changing r;l,r->visiting l,visiting r if (nl<=l&&nr>=r){ans[p]=(ans[p]+(r-l+1)*k)%mod,tag[p]=(tag[p]+k)%mod;return;} ll mid=(l+r)>>1; push_down(p,l,r); if (nl<=mid)change(lson(p),nl,nr,l,mid,k); if (nr>mid)change(rson(p),nl,nr,mid+1,r,k); push_up(p); } inline ll ask(ll p,ll nl,ll nr,ll l,ll r){ if (nl<=l&&nr>=r)return ans[p]; ll mid=(l+r)>>1,res=0; push_down(p,l,r); if (nl<=mid)res=(res+ask(lson(p),nl,nr,l,mid))%mod; if (nr>mid)res=(res+ask(rson(p),nl,nr,mid+1,r))%mod; return res; } }tree; inline void add(int u,int v){ to[++bian]=v; nxt[bian]=beg[u]; beg[u]=bian; } inline void dfs1(int x){ siz[x]=1; for (int i=beg[x];i;i=nxt[i]){ if (to[i]==fa[x])continue; fa[to[i]]=x; dep[to[i]]=dep[x]+1; dfs1(to[i]); siz[x]+=siz[to[i]]; if (siz[to[i]]>siz[son[x]])son[x]=to[i]; } } inline void dfs2(int x,int y){ top[x]=y;id[x]=++tot;num[tot] = x; if (son[x])dfs2(son[x],y); for (int i=beg[x];i;i=nxt[i]){ if (to[i]==fa[x]||to[i]==son[x])continue; dfs2(to[i],to[i]); } } int query(int x,int y){ int ans=0; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]])swap(x,y); ans=(ans+tree.ask(1,id[top[x]],id[x],1,n))%mod; x=fa[top[x]]; } if (dep[x]<dep[y])swap(x,y); ans=(ans+tree.ask(1,id[y],id[x],1,n))%mod; return ans; } void chge(int x,int y,int k){ k%=mod; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]])swap(x,y); tree.change(1,id[top[x]],id[x],1,n,k); x=fa[top[x]]; } if (dep[x]<dep[y])swap(x,y); tree.change(1,id[y],id[x],1,n,k); } signed main(){ scanf ("%lld%lld%lld%lld",&n,&m,&r,&mod);fa[r]=0,dep[r]=1; for (int i=1;i<=n;i++)scanf ("%lld",&tree.a[i]); for (int i=1;i<n;i++){ int a,b; scanf("%lld%lld",&a,&b); add(a,b),add(b,a); } dfs1(r); dfs2(r,r); tree.build(1,1,n); while(m--){ int flag,x,y,k; scanf ("%lld",&flag); switch (flag){ case 1:scanf ("%lld%lld%lld",&x,&y,&k);chge(x,y,k);break; case 2:scanf ("%lld%lld",&x,&y);printf("%lld\n",query(x,y));break; case 3:scanf ("%lld%lld",&x,&k);tree.change(1,id[x],id[x]+siz[x]-1,1,n,k);break; case 4:scanf ("%lld",&x);printf("%lld\n",tree.ask(1,id[x],id[x]+siz[x]-1,1,n)); } } } ``` 这份应该能[A](https://www.luogu.org/recordnew/show/20744590)了,里面大概有几个问题 - 宁好像总是把线段树的root = 1和原树的r搞混了,在链加和链查询函数里面(或者可能其他地方也有) - 好像有个地方宁的 ```res = (res + ...) % mod``` 写成了```res = (...)%mod``` 别的并不知道还有没有,上边那份是蒟蒻在宁的代码上进行了一番魔改的结果_(:з」∠)_宁可以两份对着查一查 ~~不说了去打游戏了~~
by kma_093 @ 2019-07-13 17:30:31


@[kma_093](/space/show?uid=43515) r和1混淆是不存在的……只是手癌晚期而已 反正谢谢大佬orz
by 引领天下 @ 2019-07-13 21:49:22


@[Aiming_High](/space/show?uid=87393) @[nosta](/space/show?uid=125139) 怕线段树出锅,所以就直接使用我之前封装的了
by 引领天下 @ 2019-07-13 22:13:52


|