[HNOI2015]开店

题面在这里

题意

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

数据范围

\[n\le1.5\times10^5,Q\le2\times10^5,A<=10^9 \]

sol

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

线段树标记永久化

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

修改

假设我们现在打了一个\(modify(l,r,x,y)\)函数,
询问区间为\([x,y]\),目前线段树的区间为\([l,r]\);
当到达底部\((x\le 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\),当到达底部\((x\le l\ \&\&\ r \le y)\)的时候,
把之前所有\(lazy\)的和\(\times\)底部节点的权值就可以了

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

#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\n",ans=dep[u]*(r-l+1)+sumdis[r]-sumdis[l-1]-2*(ask(r,u)-ask(l-1,u)));
	}
	return 0;
}

zsy大佬是最强的!!!

posted @ 2018-04-03 16:16  cjfdf  阅读(117)  评论(0编辑  收藏  举报