[HNOI2015]开店

题面在这里

题意

一棵(n)个节点的树,树上每个节点有一个权值(v[i]),边有边权(w[e]),
给出(Q)次询问,对于每次询问((u,L,R)),求点权在([L,R])的点到(u)的路径长度之和
强制在线~

数据范围

[nle1.5 imes10^5,Qle2 imes10^5,A<=10^9 ]

sol

不考虑点权,如果仅求所有点到(u)的距离该怎么做?
(ecausesum_{v=1}^{n}dist(u,v)=sum_{v=1}^{n}dep[v]+n imes dep[u]-2 imessum_{v=1}^{n}dep[lca(u,v)]),
(sum_{v=1}^{n}dep[v]),(n imes dep[u])都可以利用前缀和求出;
瓶颈在于求(sum_{v=1}^{n}dep[lca(u,v)]);
如何求?首先将所有节点进行路径覆盖((v,rt)),
最后答案即为(u)(rt)的路径(()边权( imes)覆盖次数())之和
这个可以使用树链剖分做
当有点权([L,R])的限制的时候离散化+主席树做前缀和即可
时间和空间应该都是(O(nlog^2n))的...

线段树标记永久化

第一次写居然是在主席树上...
主要思想是修改时直接在对应的节点打(lazy),询问时直接把标记往下带
具体实现:

修改

假设我们现在打了一个(modify(l,r,x,y))函数,
询问区间为([x,y]),目前线段树的区间为([l,r]);
当到达底部((xle l && r le y))的时候,我们直接打(lazy)(不需要加(sum))就可以了
回溯上来的时候,由于(lazy)节点的祖先节点在询问时访问不到这个(lazy),
我们就需要把打了这个(lazy)后对祖先节点的影响直接加到祖先节点上

如果我们需要支持区间加,像这样

#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
int sum[N<<4],lazy[N<<4];
void modify(int i,int l,int r,int x,int y,int add){
    //这个是线段树版本,主席树的下面有
    if(x<=l&&r<=y){lazy[i]+=add;return;}
    sum[i]+=add*(y-x+1);
    if(y<=mid)modify(ls,l,mid,x,y,add);
    else if(x>mid)modify(rs,mid+1,r,x,y,add);
    else modify(ls,l,mid,x,mid,add),modify(rs,mid+1,r,mid+1,y,add);
}

询问

知道(lazy)标记是怎么来的就好办了,
我们知道此时一个线段树节点的(lazy)标记是其所有祖先(lazy)标记的总和,
于是一路下来加好(lazy),当到达底部((xle l && r le y))的时候,
把之前所有(lazy)的和( imes)底部节点的权值就可以了

如果我们需要支持区间求和(爆精度什么的我才不管呢),像这样

#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
int sum[N<<4],lazy[N<<4];
int query(int i,int l,int r,int x,int y){
    //这个是线段树版本,主席树的下面有
    RG int ret=sum[i];
    if(x<=l&&r<=y)return ret+lz[i]*(y-x+1);
    if(y<=mid)return ret+query(ls,l,mid,x,y);
    else if(x>mid)return ret+query(rs,mid+1,r,x,y);
    else return ret+query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y);
}

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int N=150010;
const int M=150*N;
il ll read(){
	RG ll data=0,w=1;RG char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
	return data*w;
}

il void file(){
	freopen("shop10.in","r",stdin);
	freopen("a.out","w",stdout);
}

struct node{
	int x,y;
	bool operator <(const node b)const{
		if(x==b.x)return y<b.y;
		return x<b.x;
	}
}a[N];
int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnte;
ll sumE[N];
il void add(int u,int v,int w){
	to[++cnte]=v;
	nxt[cnte]=head[u];
	val[cnte]=w;
	head[u]=cnte;
}
int n,Q,A,rt[N],cnt;
struct tree{int ls,rs,tag;ll sum;}t[M];

int fa[N],sz[N],son[N];ll dep[N];
void dfs1(int u,int f){
	fa[u]=f;sz[u]=1;
	for(RG int i=head[u];i;i=nxt[i]){
		RG int v=to[i];if(v==fa[u])continue;
		dep[v]=dep[u]+val[i];dfs1(v,u);
		sz[u]+=sz[v];if(sz[v]>sz[son[u]])son[u]=v;
	}
}

int dfn[N],top[N];
void dfs2(int u,int tp){
	top[u]=tp;dfn[u]=++cnt;
	sumE[cnt]=dep[u]-dep[fa[u]];
	if(son[u])dfs2(son[u],tp);
	for(RG int i=head[u];i;i=nxt[i]){
		RG int v=to[i];if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}

#define mid ((l+r)>>1)
void build(int &i,int l,int r){
	i=++cnt;if(l==r)return;
	build(t[i].ls,l,mid);build(t[i].rs,mid+1,r);
}

void modify(int &i,int l,int r,int x,int y){
	t[++cnt]=t[i];i=cnt;
	if(l==x&&r==y){t[i].tag++;return;}
	t[i].sum+=sumE[y]-sumE[x-1];
	if(y<=mid)modify(t[i].ls,l,mid,x,y);
	else if(x>mid)modify(t[i].rs,mid+1,r,x,y);
	else modify(t[i].ls,l,mid,x,mid),modify(t[i].rs,mid+1,r,mid+1,y);
}

ll query(int &i,int l,int r,int x,int y){
	RG ll ret=1ll*t[i].tag*(sumE[y]-sumE[x-1]);
	if(l==x&&r==y)return ret+t[i].sum;
	if(y<=mid)return ret+query(t[i].ls,l,mid,x,y);
	else if(x>mid)return ret+query(t[i].rs,mid+1,r,x,y);
	else return ret+query(t[i].ls,l,mid,x,mid)+query(t[i].rs,mid+1,r,mid+1,y);
}

ll sumdis[N],ans;
il ll ask(int k,int u){
	ll ret=0;
	while(top[u]^1)
		ret+=query(rt[k],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
	ret+=query(rt[k],1,n,1,dfn[u]);return ret;
}

int main()
{
	n=read();Q=read();A=read();
	for(RG int i=1;i<=n;i++)a[i]=(node){read(),i};
	sort(a+1,a+n+1);
	for(RG int i=1,aa,b,c;i<n;i++){
		aa=read();b=read();c=read();
		add(aa,b,c);add(b,aa,c);
	}
	dfs1(1,0);dfs2(1,1);cnt=0;build(rt[0],1,n);
	for(RG int i=1;i<=n;i++)
		sumE[i]+=sumE[i-1],sumdis[i]+=sumdis[i-1]+dep[a[i].y];
	for(RG int i=1;i<=n;i++){
		RG int u=a[i].y;rt[i]=rt[i-1];
		while(top[u]^1)modify(rt[i],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
		modify(rt[i],1,n,1,dfn[u]);
	}
	for(RG int i=1,u,l,r;i<=Q;i++){
		u=read();l=(read()+ans)%A;r=(read()+ans)%A;
		if(l>r)swap(l,r);
		l=lower_bound(a+1,a+n+1,(node){l,0})-a;
		r=upper_bound(a+1,a+n+1,(node){r,n})-a-1;
		printf("%lld
",ans=dep[u]*(r-l+1)+sumdis[r]-sumdis[l-1]-2*(ask(r,u)-ask(l-1,u)));
	}
	return 0;
}

zsy大佬是最强的!!!

原文地址:https://www.cnblogs.com/cjfdf/p/8709155.html