一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化

LINK:简单树

以后我再不认真读题 我TM活该退役

又因为没认真读题多调了20min.时间珍贵啊。

题目最后让ans%n 我没取模 自闭ing.

还是挺有意思的题目。求x到区间[L,R]的所有点的距离。

这个还是一个非常经典的问题。需要把答案的式子列出来。

\(\sum_{i=L}^R(dis_x+dis_i-dis_{lca(i,x)})\)

前面两项都可以直接计算/预处理得到。

后面这个东西 看似很难求 考虑 将所有i到根的路径上每一条边赋上权值 然后x向上爬路过的边如果存在权值 那么就是\(dis_{lca(i,x)}\)了。

这个东西可以利用树链刨分进行快速赋值 而区间问题使用 可持久化线段树即可。

由于不能下传懒标记 所以需要标记永久化一下。

const int MAXN=60010;
int n,m,T,len,id,cnt;
int root[MAXN];
int f[MAXN],son[MAXN],dfn[MAXN],top[MAXN],pos[MAXN],d[MAXN],sz[MAXN];
ll dis[MAXN],sum[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
struct wy
{
	int l,r;
	ll sum;
	int s;
}t[MAXN*400];
inline void add(int x,int y,int z)
{
	ver[++len]=y;
	nex[len]=lin[x];
	lin[x]=len;
	e[len]=z;
}
inline void dfs(int x,int fa)
{
	f[x]=fa;d[x]=d[fa]+1;sz[x]=1;
	go(x)if(tn!=fa)
	{
		dis[tn]=dis[x]+e[i];
		dfs(tn,x);
		sz[x]+=sz[tn];
		if(sz[tn]>sz[son[x]])son[x]=tn;
	}
}
inline void dp(int x,int fa)
{
	top[x]=fa;dfn[x]=++id;pos[id]=x;
	if(son[x])dp(son[x],fa);
	go(x)if(tn!=f[x]&&tn!=son[x])dp(tn,tn);
}
inline void insert(int &p,int las,int l,int r,int L,int R)
{
	p=++cnt;t[p]=t[las];
	if(L==l&&R==r){++s(p);return;}
	sum(p)+=dis[pos[R]]-dis[f[pos[L]]];
	int mid=(l+r)>>1;
	if(R<=mid)insert(l(p),l(las),l,mid,L,R);
	else
	{
		if(L>mid)insert(r(p),r(las),mid+1,r,L,R);
		else insert(l(p),l(las),l,mid,L,mid),insert(r(p),r(las),mid+1,r,mid+1,R);
	}
}
inline ll ask(int p,int las,int l,int r,int L,int R)
{
	if(l==L&&R==r)
	{
		//cout<<(s(p)-s(las))<<' '<<s(p)<<endl;
		return sum(p)-sum(las)+(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
	}
	int mid=(l+r)>>1;
	ll cnt=(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
	if(R<=mid)return cnt+ask(l(p),l(las),l,mid,L,R);
	if(L>mid)return cnt+ask(r(p),r(las),mid+1,r,L,R);
	return cnt+ask(l(p),l(las),l,mid,L,mid)+ask(r(p),r(las),mid+1,r,mid+1,R);
}
int main()
{
	//freopen("1.in","r",stdin);
	get(n);get(m);get(T);
	rep(2,n,i)
	{
		int get(x),get(y),get(z);
		add(x,y,z);add(y,x,z);
	}
	dfs(1,0);dp(1,1);
	rep(1,n,i)sum[i]=sum[i-1]+dis[i];
	rep(1,n,i)
	{
		int x=i;
		while(top[x]!=1)
		{
			insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[top[x]],dfn[x]);
			x=f[top[x]];
		}
		if(x!=1)insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[1]+1,dfn[x]);
	}
	ll ans=0;
	rep(1,m,i)
	{
		int L,R,x;
		get(L)^(ans*T);
		get(R)^(ans*T);
		get(x)^(ans*T);
		ans=dis[x]*(R-L+1)+sum[R]-sum[L-1];
		while(top[x]!=1)
		{
			ans-=2*ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x]);
			//cout<<ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x])<<endl;
			x=f[top[x]];
		}
		if(x!=1)ans-=2*ask(root[R],root[L-1],1,n,dfn[1]+1,dfn[x]);
		putl(ans);ans%=n;
	}
	return 0;
}
上一篇:Luogu P5329 [SNOI2019]字符串


下一篇:Java8 的 StringJoiner类