bzoj4012: [HNOI2015]开店

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4012

思路:首先我们考虑一个简化的问题:

给定一棵树,每次询问所有点到一个点的距离和。


画个图就能知道:距离和=所有点到根的距离和+点数*u到根的距离-每个点与u的lca到根的距离*2


于是问题就成了求lca的dis和


那么我们先对每个点,把它到根的路径覆盖一次,然后询问点u时就是从u向上跳,每次加覆盖次数*边权

用树链剖分即可

但是现在每个点多了一个点权,有了限制条件:只计算点权要在[l,r]内的点到u的距离。

对于区间最大最小等问题我们用的是线段树,对于区间内且权值在[a,b]间的点的询问,我们就用可持久化线段树。


这题也一样,先按点权(年龄)从小到大排序,离散化,按点权顺序把每个点到根的路径覆盖一次。

像对序列的问题一样,询问年龄在[l,r]中的lca的dis和,就是[1,r]的距离和-[1,l]的距离和。

然后就没有然后了


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=150010,maxm=300010,maxt=10000010;
typedef long long ll;
using namespace std;
int n,m,mod,age[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot,tim;
int last[maxn],root[maxn],rt; ll ans,sumdis[maxn],sumE[maxn],dis[maxn];
int top[maxn],dep[maxn],hson[maxn],dfn[maxn],fa[maxn],siz[maxn];
struct Monster{int age,id;}mon[maxn];
void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
bool operator<(Monster a,Monster b){return a.age!=b.age?a.age<b.age:a.id<b.id;}

struct TSegment_tree{
	ll sum[maxt];int ls[maxt],rs[maxt],tot,time[maxt];
	int modify(int p,int l,int r,int a,int b){
		int x=++tot,mid=(l+r)>>1;
		ls[x]=ls[p],rs[x]=rs[p],sum[x]=sum[p],time[x]=time[p];
		if (l==a&&r==b){time[x]++;return x;}
		sum[x]+=(sumE[b]-sumE[a-1]);
		if (b<=mid) ls[x]=modify(ls[x],l,mid,a,b);
		else if (a>mid) rs[x]=modify(rs[x],mid+1,r,a,b);
		else ls[x]=modify(ls[x],l,mid,a,mid),rs[x]=modify(rs[x],mid+1,r,mid+1,b);
		return x;
	}
	ll query(int p,int l,int r,int a,int b){
		ll res=1ll*(sumE[b]-sumE[a-1])*time[p];
		if (l==a&&r==b){return res+sum[p];}
		int mid=(l+r)>>1;
		if (b<=mid) return res+query(ls[p],l,mid,a,b);
		else if (a>mid) return res+query(rs[p],mid+1,r,a,b);
		else return res+query(ls[p],l,mid,a,mid)+query(rs[p],mid+1,r,mid+1,b);
	}
}T;

void dfs(int x){
	siz[x]=1;
	for (int y=now[x];y;y=pre[y])if (son[y]!=fa[x]){
		fa[son[y]]=x,dis[son[y]]=dis[x]+val[y],last[son[y]]=val[y];
		dfs(son[y]),siz[x]+=siz[son[y]];
		if (siz[son[y]]>siz[hson[x]]) hson[x]=son[y];
	}
}

void btree(int x,int tp){
	sumE[dfn[x]=++tim]=last[x],top[x]=tp;
	if (hson[x]) btree(hson[x],tp);
	for (int y=now[x];y;y=pre[y])
		if (hson[x]!=son[y]&&son[y]!=fa[x])
			btree(son[y],son[y]);
}

int modify(int x){
	while (top[x]!=1){rt=T.modify(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
	return rt=T.modify(rt,1,n,1,dfn[x]);
}

ll query(int rt,int x){
	ll res=0;
	while (top[x]!=1){res+=T.query(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
	return res+T.query(rt,1,n,1,dfn[x]);
}

int main(){
	scanf("%d%d%d",&n,&m,&mod);
	for (int i=1;i<=n;i++) scanf("%d",&mon[i].age),mon[i].id=i;
	sort(mon+1,mon+1+n);
	for (int i=1,a,b,c;i<n;i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c);
	dfs(1),btree(1,1);
	for (int i=1;i<=n;i++) sumE[i]+=sumE[i-1],sumdis[i]=sumdis[i-1]+dis[mon[i].id];
	for (int i=1;i<=n;i++) root[i]=modify(mon[i].id);
	for (int i=1,a,b,u;i<=m;i++){
		scanf("%d%d%d",&u,&a,&b);
		a=(1ll*a+ans)%mod,b=(1ll*b+ans)%mod;
		if (a>b) swap(a,b);
		a=lower_bound(mon+1,mon+1+n,(Monster){a,0})-mon,b=upper_bound(mon+1,mon+1+n,(Monster){b,(int)1e9})-mon-1;
		ans=1ll*(b-a+1)*dis[u]+sumdis[b]-sumdis[a-1]-2ll*((query(root[b],u)-query(root[a-1],u)));
		printf("%lld\n",ans);
	}
	return 0;
}






posted @ 2015-12-18 12:23  orzpps  阅读(103)  评论(0编辑  收藏  举报