法一
一个点到所有点距离?
树上路径问题,从一个点出发的
虽然不是统计一次,虽然强制在线,点分治也可以做!
因为可以动态点分治的分治树来搞!
vector维护到根路径dis,按age sort之后,处理后缀和
再维护到分治树father的贡献
O(nlog^2n)
代码:
#pragma GCC optimize("O2,Ofast,inline,unroll-all-loops,-ffast-math") #pragma GCC target("avx,sse2,sse3,sse4,popcnt") #include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar(' ');} namespace Miracle{ const int N=150000+5; const int inf=0x3f3f3f3f; int n,q,A; int age[N]; struct node{ int nxt,to,val; }e[2*N]; int hd[N],cnt; void add(int x,int y,int z){ e[++cnt].nxt=hd[x]; e[cnt].to=y;e[cnt].val=z;hd[x]=cnt; } int sz[N],nowsz; struct po{ int id,dis; ll bac; po(){} po(int dd,int ds){ id=dd;dis=ds;bac=ds; } bool friend operator <(po a,po b){ if(a.id!=b.id) return a.id<b.id; return a.dis<b.dis; } void op(){ cout<<" id "<<id<<" dis "<<dis<<" bac "<<bac<<endl; } }; vector<po>mem[N]; int dis[N][19]; int fa[N]; vector<po>df[N]; int rt;//,sz[N]; int vis[N]; int dep[N]; void fin(int x,int fa){ sz[x]=1; int mxsz=0; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa||vis[y]) continue; fin(y,x); sz[x]+=sz[y]; mxsz=max(mxsz,sz[y]); } mxsz=max(mxsz,nowsz-sz[x]); if(mxsz<=nowsz/2){ rt=x; } } void dfs2(int x,int fa,int d){ sz[x]=1; if(d!=1) df[rt].push_back(po(age[x],dis[x][d-1])); mem[rt].push_back(po(age[x],dis[x][d])); for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa||vis[y]) continue; dis[y][d]=dis[x][d]+e[i].val; dfs2(y,x,d); sz[x]+=sz[y]; } } void divi(int x,int d,int f){ // cout<<" divi "<<x<<" d "<<d<<" f "<<f<<" nowsz "<<nowsz<<endl; rt=0; fin(x,0); // cout<<" rt "<<rt<<endl; dep[rt]=d; fa[rt]=f; dfs2(rt,0,d); if(d!=1){ sort(df[rt].begin(),df[rt].end()); for(reg i=df[rt].size()-2;i>=0;--i){ df[rt][i].bac=df[rt][i+1].bac+df[rt][i].dis; } } sort(mem[rt].begin(),mem[rt].end()); for(reg i=mem[rt].size()-2;i>=0;--i){ mem[rt][i].bac=mem[rt][i+1].bac+mem[rt][i].dis; } vis[rt]=1; int tmp=rt; for(reg i=hd[tmp];i;i=e[i].nxt){ int y=e[i].to; if(!vis[y]){ nowsz=sz[y]; divi(y,d+1,tmp); } } } ll wrk(int x,int L,int R){ ll ret=0; int le=lower_bound(mem[x].begin(),mem[x].end(),po(L,-1))-mem[x].begin(); int ri=upper_bound(mem[x].begin(),mem[x].end(),po(R,inf))-mem[x].begin(); if(le!=mem[x].size()) ret+=mem[x][le].bac; if(ri!=mem[x].size()) ret-=mem[x][ri].bac; // cout<<"start "<<ret<<endl; int st=x; while(fa[x]){ int y=fa[x]; // cout<<" yy "<<y<<" dis "<<dis[st][dep[y]]<<endl; // for(reg i=0;i<mem[y].size();++i){ // cout<<" i "<<i+1;mem[y][i].op();cout<<endl; // } int le=lower_bound(mem[y].begin(),mem[y].end(),po(L,-1))-mem[y].begin(); int ri=upper_bound(mem[y].begin(),mem[y].end(),po(R,inf))-mem[y].begin(); // cout<<" le ri "<<le<<" "<<ri<<endl; if(le!=mem[y].size()) ret+=mem[y][le].bac,ret+=(ll)(mem[y].size()-le)*dis[st][dep[y]]; if(ri!=mem[y].size()) ret-=mem[y][ri].bac,ret-=(ll)(mem[y].size()-ri)*dis[st][dep[y]]; // cout<<" ret before dele "<<ret<<endl; le=lower_bound(df[x].begin(),df[x].end(),po(L,-1))-df[x].begin(); ri=upper_bound(df[x].begin(),df[x].end(),po(R,inf))-df[x].begin(); if(le!=df[x].size()) ret-=df[x][le].bac,ret-=(ll)(df[x].size()-le)*dis[st][dep[y]]; if(ri!=df[x].size()) ret+=df[x][ri].bac,ret+=(ll)(df[x].size()-ri)*dis[st][dep[y]]; x=fa[x]; } return ret; } int main(){ rd(n);rd(q);rd(A); for(reg i=1;i<=n;++i) rd(age[i]); int x,y,z; for(reg i=1;i<n;++i){ rd(x);rd(y);rd(z);add(x,y,z);add(y,x,z); } nowsz=n; divi(1,1,0); ll ans=0; int a,b,L,R; while(q--){ rd(x);rd(a);rd(b); L=min((a+ans)%A,(b+ans)%A),R=max((a+ans)%A,(b+ans)%A); // cout<<" true "<<x<<" "<<L<<" "<<R<<endl; printf("%lld ",ans=wrk(x,L,R)); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/3/23 19:57:03 */
法二:
两个点距离怎么算?
距离差分?
考虑距离是怎么算的,∑dis+n*dis(x)-2*dis(lca)
前面两个好算
考虑每个点贡献作为lca应有的贡献,也就是经过的sz
暴力跳不行,考虑树剖!
考虑x头上的边贡献
无[L,R]限制,直接把每个点到根的链上的sz++,
有[L,R],主席树rt按照age,主席树的叶子下标是dfn序,权值是[1,i]颜色的fdfn[p]的子树的个数和
加入一个点,重链跳,主席树标记永久化区间加
查询时候,找一段链作为lca的贡献,就是主席树差分查区间和
注意减去u子树的贡献
一个点有时候携带多个信息
一个区间的点的信息查询可以用主席树
树链的点的信息查询,树剖+主席树!