【BZOJ4012】【HNOI2015】—开店(动态点分治)

传送门

感觉和幻想乡那道题差别不是很大

每一层排序后用一个数据结构来维护
因为没有修改直接每个点维护子树信息
排序后每次询问二分前缀和就可以了

记录一下每个点自己的答案和对父亲的贡献
相减一下就可以了

具体可以参考代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pb push_back
const int RLEN=1<<22|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=1;ch=gc();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return res*f;
}
const int N=150005;
struct Mos{
	int old,dis;ll sum;
	Mos(int o=0,int d=0,ll s=0):old(o),dis(d),sum(s){}
	friend inline bool operator <(const Mos &a,const Mos &b){
		return a.old<b.old;
	}
};
vector<Mos> f1[N],f2[N];
int adj[N],nxt[N<<1],to[N<<1],val[N<<1],lg[N<<2],siz[N],pos[N],son[N],maxn,dfn,rt,cnt,fa[N],vis[N];
int n,q,A,x[N];
ll st[N<<2][22],dis[N];
inline void addedge(int u,int v,int w){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
void dfs(int u,int f){
	st[++dfn][0]=dis[u],pos[u]=dfn;
	for(re int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==f)continue;
		dis[v]=dis[u]+val[e];
		dfs(v,u),st[++dfn][0]=dis[u];
	}
}
inline void init(){
	dfs(1,0),lg[0]=-1;
	for(re int i=1;i<=n*4;i++)lg[i] = lg[i >> 1] + 1;
	for(re int i=1;(1<<i)<=dfn;i++){
		for(re int j=1;j+(1<<i)-1<=dfn;j++){
			st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
		}
	}
}
inline ll dist(int u,int v){
	int x=pos[u],y=pos[v];
	if(x>y)swap(x,y);
	int t=lg[y-x+1];
	return dis[u]+dis[v]-2*min(st[x][t],st[y-(1<<t)+1][t]);
}
void getrt(int u,int f){
	siz[u]=1,son[u]=0;
	for(re int e=adj[u];e;e=nxt[e]){
		int v=to[e];if(v==f||vis[v])continue;
		getrt(v,u),siz[u]+=siz[v];
		if(siz[v]>son[u])son[u]=siz[v];
	}
	son[u]=max(son[u],maxn-siz[u]);
	if(son[u]<son[rt])rt=u;
}
void solve(int u){
	vis[u]=1;
	for(re int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(vis[v])continue;
		son[0]=maxn=siz[v],getrt(v,rt=0),fa[rt]=u,solve(rt);
	}
}
inline ll query(int u,int k){
	ll res=0;
	for(re int i=u;i;i=fa[i]){
		int p=lower_bound(f1[i].begin(),f1[i].end(),Mos(k,0,0))-f1[i].begin()-1;
		res+=f1[i][p].sum+1ll*p*dist(u,i);
	}
	for(re int i=u;fa[i];i=fa[i]){
		int p=lower_bound(f2[i].begin(),f2[i].end(),Mos(k,0,0))-f2[i].begin()-1;
		res-=f2[i][p].sum+1ll*p*dist(u,fa[i]);
	}
	return res;
}
int main(){
//	freopen("lx.cpp","r",stdin);
	n=read(),q=read(),A=read();
	for(int i=1;i<=n;i++)x[i]=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read(),w=read();
		addedge(u,v,w),addedge(v,u,w);
	}
	maxn=son[0]=n;
	init(),getrt(1,rt=0);solve(rt);
	for(re int i=1;i<=n;i++){
		for(re int u=i;u;u=fa[u]){
			f1[u].pb(Mos(x[i],dist(u,i),0)),f2[u].pb(Mos(x[i],dist(fa[u],i),0));
		}
	}
	for(re int u=1;u<=n;u++){
		f1[u].pb(Mos(-1,0,0)),f1[u].pb(Mos(RLEN,0,0));
		f2[u].pb(Mos(-1,0,0)),f2[u].pb(Mos(RLEN,0,0));
		sort(f1[u].begin(),f1[u].end());
		sort(f2[u].begin(),f2[u].end());
		for(re int j=1;j<f1[u].size();j++)f1[u][j].sum=f1[u][j].dis+f1[u][j-1].sum;
		for(re int j=1;j<f2[u].size();j++)f2[u][j].sum=f2[u][j].dis+f2[u][j-1].sum;
	}
	ll last=0;
	for(re int i=1;i<=q;i++){
		int u=read(),x=read(),y=read();
		x=(x+last)%A,y=(y+last)%A;
		if(x>y)swap(x,y);
		cout<<(last=(query(u,y+1)-query(u,x)))<<'\n';
	}
}
posted @ 2019-03-30 19:52  Stargazer_cykoi  阅读(148)  评论(0编辑  收藏  举报