【BZOJ】4012: [HNOI2015]开店

时间:2023-03-09 13:37:53
【BZOJ】4012: [HNOI2015]开店

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012


给出一个$n$个点的树,树上每一个点都有一个值$age$,每条边都有边权,每次查询一个点,求出树中所有点上权值${L<=age[i]<=R}$的点到它的距离的和。


为了学习传说中的动态树分治,我就把这个题当作模板题来写了。

当然这题也可以树链剖分+权值线段树

  为什么叫做动态树分治?其实就是把分治的结构记录了下来,树分治的好处在于每一次操作(找出当前块重心并再次递归)可以快速减少树的大小,我们记录下这个每次求出的树的重心的结构,这样的分治结构是严格log层的,每一次查询的是沿着分治结构构出的树往上跳,统计所有点到当前点的距离(这里需要数据结构维护,可以开一个vector动态记录每一个点在分治中所管辖的子树的所有点的信息,然后查询的时候二分即可),然后再往分治结构构成的树的父亲上跳,因为在分治结构的父亲所管辖的子树一定包含了当前点所管辖的子树,所以需要容斥(全是细节)。复杂度${O(nlog^{2})}$

  可怕的是BZOJ上似乎卡常?


code:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<ctime>
using namespace std;
#define maxn 600100
#define llg long long
#define RG register llg
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg Q,A,n,m,age[maxn],ans,dad[maxn],dadv[maxn],maxage,f[maxn][],dis[maxn][],deep[maxn];
bool bj[maxn],bj_[maxn];
llg g[maxn<<],maxl,weizhi,dl[maxn],tail,L,R,o,te,buf[]; inline void write(RG x)
{
if (x<) putchar('-'),x=-x;
buf[]=;
while (x) buf[++buf[]]=x%,x/=;
if (!buf[]) buf[]=,buf[]=;
while (buf[]) putchar(''+buf[buf[]--]);
putchar('\n');
} inline llg getint()
{
llg w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} struct edge{
int y,next;
llg d;
}e[maxn<<]; void addedge(RG x,RG y,RG d){
e[++te].y=y;
e[te].d=d;
e[te].next=g[x];
g[x]=te;
} struct node
{
llg age,dis,qz,qz_,dis_;
};
inline bool cmp(const node&a,const node&b) {return a.age<b.age;} vector<node>c[maxn]; inline void clear_() {for (RG i=;i<=tail;i++) bj_[dl[i]]=; tail=;} inline void dfs(RG x,RG fa)
{
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (v==fa) continue;
f[v][]=x; dis[v][]=e[i].d;
deep[v]=deep[x]+;
dfs(v,x);
}
} inline void make_f()
{
for (RG j=;j<=;j++)
for (RG i=;i<=n;i++)
{
f[i][j]=f[f[i][j-]][j-];
dis[i][j]=dis[i][j-]+dis[f[i][j-]][j-];
}
} inline llg find_dis(RG x,RG y)
{
if (x== || y==) return ;
RG ans=;
if (deep[x]<deep[y]) swap(x,y);
for (RG i=;i>=;i--)
if (deep[f[x][i]]>=deep[y])
{
ans+=dis[x][i];
x=f[x][i];
}
if (x==y) return ans;
for (RG i=;i>=;i--)
if (f[x][i]!=f[y][i])
{
ans+=dis[x][i]+dis[y][i];
x=f[x][i],y=f[y][i];
}
return ans+dis[x][]+dis[y][];
} void init()
{
RG x,y,z;
cin>>n>>Q>>A;
for (RG i=;i<=n;i++) age[i]=getint(),maxage=max(maxage,age[i]);
for (RG i=;i<n;i++)
{
x=getint(),y=getint(),z=getint();
addedge(x,y,z);
addedge(y,x,z);
}
deep[]=;
dfs(,);
make_f();
} inline llg find_size(RG x)
{
bj_[x]=;
dl[++tail]=x;
RG tot=;
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
tot+=find_size(v);
}
return tot;
} inline llg dp(RG x,RG size)
{
bj_[x]=;
dl[++tail]=x;
RG tot=,ma=;
for (register llg i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
RG he=dp(v,size);
ma=max(ma,he);
tot+=he;
}
ma=max(size-tot,ma);
if (ma<maxl)
{
maxl=ma;
weizhi=x;
}
return tot;
} inline llg find_root(RG x)
{
clear_();
RG size=find_size(x);
clear_();
maxl=n+; weizhi=-;
dp(x,size);
return weizhi;
} inline void dfs_c(RG x,RG now)
{
bj_[x]=; dl[++tail]=x;
node E;
E.age=age[x]; E.dis=find_dis(x,now); E.dis_= find_dis(x,dad[now]);
c[now].push_back(E);
for (RG i=g[x];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v] || bj_[v]) continue;
dfs_c(v,now);
}
} inline void solve( RG now,RG fa)
{
RG ne=find_root(now);
now=ne;
dadv[now]=find_dis(now,fa);
bj[now]=;
dad[now]=fa;
clear_();
dfs_c(now,now);
for (RG i=g[now];i;i=e[i].next)
{
RG v=e[i].y;
if (bj[v]) continue;
solve(v,now);
}
RG si=c[now].size();
sort(c[now].begin(),c[now].end(),cmp);
c[now][].qz=c[now][].dis;
c[now][].qz_=c[now][].dis_;
for (RG i=;i<si;i++)
{
c[now][i].qz=c[now][i-].qz+c[now][i].dis;
c[now][i].qz_=c[now][i-].qz_+c[now][i].dis_;
}
} void read() {RG x,y; x=getint(),y=getint(); L=min((x+ans)%A,(y+ans)%A); R=max((x+ans)%A,(y+ans)%A);} inline llg erfen(RG x, RG V,RG dis_,bool pd)
{
RG l=,r=c[x].size()-,mid,wz=-;
while (l<=r)
{
mid=(l+r)>>;
if (c[x][mid].age<=V) {wz=mid; l=mid+;}else{r=mid-;}
}
if (wz==-) return ;
if (pd) return c[x][wz].qz+(dis_-find_dis(dad[x],o))*(wz+)-c[x][wz].qz_;
else return c[x][wz].qz_+(wz+)*(find_dis(dad[x],o)-dis_)-c[x][wz].qz;
} inline llg erfen_(RG x,RG V)
{
RG l=,r=c[x].size()-,mid,wz=-;
while (l<=r)
{
mid=(l+r)>>;
if (c[x][mid].age<=V) {wz=mid; l=mid+;}else{r=mid-;}
}
if (wz==-) return ;
return (wz+)*find_dis(dad[x],o)+c[x][wz].qz_;
} inline void find(register llg x)
{
RG dis_=find_dis(x,o);
// llg sum=erfen(x,R,dis_)-erfen(x,L-1,dis_);
// llg dec=erfen_(x,R)-erfen_(x,L-1);
ans+=erfen(x,R,dis_,)+erfen(x,L-,dis_,);
// ans+=sum-dec;
if (dad[x]!=) find(dad[x]);
} llg dg(llg x)
{
if (dad[x]!=) return dg(dad[x])+;
else return ;
} int main()
{
yyj("shop");
init();
solve(,);
/* for (llg i=1;i<=n;i++)
{
maxl=max(maxl,dg(i));
}
cout<<maxl; return 0;*/
while (Q--)
{
o=getint();
read();
ans=;
find(o);
write(ans);
}
// cout<<clock();
return ;
}