• [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;
    }
    
  • 相关阅读:
    iOS 数据存储
    iOS 中@property() 括号中,可以填写的属性?
    iOS 中关闭键盘方法
    iBeacons 资源汇总
    iOS7 下去掉状态栏(全屏)
    监听器HttpSessionListener
    监听器 HttpSessionBindingListener
    servlet 3.0 的使用
    工厂模式小例子 getDaoImp
    servlet和filter初始化
  • 原文地址:https://www.cnblogs.com/asuldb/p/10864567.html
Copyright © 2020-2023  润新知