[HNOI2015]开店

题目

显然这个题不强制在线我们就有一个非常优秀的树剖做法

但是现在强制在线使得这个问题变得看起来有些难搞了

于是就变成了动态点分治的板子题了

我们先建一棵点分树,对于每一个分治重心我们存一下当前分治块内所有点到这个点的距离,用一个vector存下来

我们再存一下每个点作为分治重心的时分治块内部所有点上一级分治重心的距离

每次询问我们暴力跳点分树,在vector里二分即可

代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define mp std::make_pair
#define pb push_back
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=150005;
typedef std::pair<int,int> pii;
struct E{int v,nxt,w;}e[maxn<<1];
int n,num,m,S,rt,cnt,A;
int head[maxn],pre[maxn],vis[maxn],fa[maxn],a[maxn];
int deep[maxn],b[maxn<<1],sum[maxn],mx[maxn],pos[maxn];
int f[maxn<<1][20],lg[maxn<<1];
inline void add(int x,int y,int w) {
	e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=w;
}
std::vector<int> son[maxn];
std::vector<LL> sg[maxn],sh[maxn];
std::vector<pii> g[maxn],h[maxn];
void getpre(int x) {
	b[++cnt]=x;pos[x]=cnt;
	for(re int i=head[x];i;i=e[i].nxt) {
		if(deep[e[i].v]) continue;
		deep[e[i].v]=deep[x]+1,pre[e[i].v]=pre[x]+e[i].w;
		getpre(e[i].v);b[++cnt]=x;
	}
}
void getroot(int x,int f) {
	sum[x]=1;mx[x]=0;
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]||f==e[i].v) continue;
		getroot(e[i].v,x);sum[x]+=sum[e[i].v];
		mx[x]=max(mx[x],sum[e[i].v]);
	}
	mx[x]=max(S-sum[x],mx[x]);
	if(mx[x]<mx[rt]) rt=x;
}
void getdis(int x,int f,int p,int t,int L) {
	g[p].pb(mp(a[x],L));h[t].pb(mp(a[x],L));
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]||f==e[i].v) continue;
		getdis(e[i].v,x,p,t,L+e[i].w); 
	}
}
void solve(int x) {
	std::sort(g[x].begin(),g[x].end());
	sg[x].pb(g[x][0].second);
	for(re int i=1;i<g[x].size();i++) 
		sg[x].pb(sg[x][i-1]+g[x][i].second);
}
void dfs(int x) {
	vis[x]=1;h[x].pb(mp(a[x],0));
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]) continue;
		rt=0,S=sum[e[i].v],getroot(e[i].v,0);fa[rt]=x;
		getdis(e[i].v,0,rt,x,e[i].w);
		solve(rt);son[x].pb(rt);
	}
	std::sort(h[x].begin(),h[x].end());
	sh[x].pb(h[x][0].second);
	for(re int i=1;i<h[x].size();i++) 
		sh[x].pb(sh[x][i-1]+h[x][i].second);
	for(re int i=0;i<son[x].size();i++) dfs(son[x][i]);
}
inline void find(int x,int t,int& tot,LL &ans) {
	int l=0,r=g[x].size()-1,c=-1;
	while(l<=r) {
		int mid=l+r>>1;
		if(g[x][mid].first<=t) l=mid+1,c=mid;
			else r=mid-1;
	}
	if(c!=-1) tot-=c+1,ans-=sg[x][c];
}
inline int LCA(int x,int y) {
	x=pos[x],y=pos[y];
	if(x>y) std::swap(x,y);
	int k=lg[y-x+1];
	if(deep[f[x][k]]<deep[f[y-(1<<k)+1][k]]) return f[x][k];
	return f[y-(1<<k)+1][k];
}
inline int dis(int x,int y) {return pre[x]+pre[y]-2*pre[LCA(x,y)];}
inline LL ask(int x,int t) {
	int p=0,k=x;LL ans=0;
	while(x) {
		int tot=0,c=-1,l=0,r=h[x].size()-1;
		while(l<=r) {
			int mid=l+r>>1;
			if(h[x][mid].first<=t) l=mid+1,c=mid;
				else r=mid-1;
		}
		if(c!=-1) tot=c+1,ans+=sh[x][c];
		if(p) find(p,t,tot,ans);
		ans+=1ll*tot*dis(x,k);
		p=x;x=fa[x];
	}
	return ans;
}
int main() {
	n=read(),m=read(),A=read();
	for(re int i=1;i<=n;i++) a[i]=read();
	for(re int x,y,w,i=1;i<n;i++) {
		x=read(),y=read(),w=read();
		add(x,y,w),add(y,x,w);
	}
	deep[1]=1;getpre(1);
	for(re int i=1;i<=2*n;i++) f[i][0]=b[i];
	for(re int i=2;i<=2*n;i++) lg[i]=lg[i>>1]+1;
	for(re int j=1;j<=lg[2*n];j++)
		for(re int i=1;i+(1<<j)-1<=2*n;i++)
			if(deep[f[i][j-1]]<deep[f[i+(1<<(j-1))][j-1]]) f[i][j]=f[i][j-1];
				else f[i][j]=f[i+(1<<(j-1))][j-1];
	mx[0]=n+1,S=n,rt=0,getroot(1,0);dfs(rt);
	LL lst=0;int u,x,y,l,r;
	while(m--) {
		u=read(),x=read(),y=read();
		l=(1ll*x+lst)%A,r=(1ll*y+lst)%A;
		if(l>r) std::swap(l,r);
		printf("%lld\n",lst=ask(u,r)-ask(u,l-1));
	}
	return 0;
}
posted @ 2019-05-14 20:58  asuldb  阅读(143)  评论(0编辑  收藏  举报