• [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
    ",lst=ask(u,r)-ask(u,l-1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    网上购物记录(2011淘宝大甩卖)
    心理学上最诡异的23张图!!
    三字念什么
    哥德尔不完备定理
    又要新的开始了(续)
    第一次接触计算机语言的经历
    哥德尔不完备性定理——从数学危机到哲学危机
    google (精简版)
    贴吧回复
    在轻松的环境中工作
  • 原文地址:https://www.cnblogs.com/asuldb/p/10864567.html
Copyright © 2020-2023  润新知