【LuoguP3241】[HNOI2015] 开店
题意
给出一棵边带权的树,多次在线询问一个点到一个区间内的点的距离和。
Sol
分块过不了的
一个 trick ,都知道要算两点之间距离可以拆成到根的距离和他们的 LCA 到根的距离 ,其实要算多个点到一个点距离也可以使用一个类似的 trick。
问题就在于快速求解所有的:$$\sum_{v\in S}deep[LCA(u,v)]$$
我们对于要询问的点集 \(S\) ,每一个点向上把所有反祖的边都覆盖一次,然后对于 \(u\) 点我们把它拿着一步步向上走,对于每一条经过的边把它被覆盖的次数与这条边的边权的积求和,最后就是上面那个式子了。
也就是说现在我们的问题是快速求出一个区间内所有点向上覆盖后某一个点向上的每条边被覆盖的次数与边权的积。
这个显然就用 主席树+树链剖分 来维护一下就可以了。
把点按顺序插入,每一个点在树上用树剖往上,每一段在内层线段树中进行修改。
不过这里是区间修改,直接打可下放标记可能会很伤空间 ,那么可以用标记永久化。
但是我们这里是区间询问,那么就要用到一些巧妙的方法。
这个方法也可以用于二维线段树等一般只适用于单点查询的问题。
观察我们的询问方式,先把我们要询问的区间分为 \(log\) 个区间,然后当当前区间被完全覆盖的时候我们为了保证复杂度肯定不能继续往下了,这样如果我们使用常规的标记永久化的话我们就有可能没办法计算到下面的点的答案了。
这样子我们就还需要维护一个标记,表示当前区间总修改量,即使当前区间没有被修改完全修改我们也要更新这个标记。
这样当我们查询到一个被询问区间完全覆盖的区间的时候我们就直接把当前区间的总修改量加上就可以了,因为我们只有当询问完全覆盖当前区间的时候才会用到这个标记,而这个标记相当于是把下面的修改信息都上传了之后的信息,就没有问题了。
code:
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void init(T&x){
	x=0;char ch=getchar();bool t=0;
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-')t=1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
	if(t) x=-x;return;
}
const int N=1.5e5+10;
int n,m,tp,RT;
typedef long long ll;
int dep[N],fa[N];ll dis[N];
struct edge{
	int to,next,w;
}a[N<<1];
int LIM;int head[N],cnt=0;
inline void add(int x,int y,int z){a[++cnt]=(edge){y,head[x],z};head[x]=cnt;}
int id[N],dfn[N],size[N],top[N],son[N],I=0,Ret[N];
namespace LISAN{
	int age[N],id[N];
	inline bool cmp(int i,int j){return age[i]<age[j];}
	inline int Lower(register int x){
		register int l=1,r=n,pos=n+1;
		while(l<=r){
			register int mid=l+r>>1;
			if(age[id[mid]]>=x) pos=mid,r=mid-1;else l=mid+1;
		}
		return pos;
	}
	void Prepare(){for(int i=1;i<=n;++i) id[i]=i,init(age[i]);sort(id+1,id+1+n,cmp);return;}
}using LISAN::Lower;
void Dfs(int u){
	size[u]=1;
	for(int v,i=head[u];i;i=a[i].next){
		v=a[i].to;if(v==fa[u]) continue;
		fa[v]=u,dep[v]=dep[u]+1;dis[v]=dis[u]+a[i].w;
		Ret[v]=a[i].w;Dfs(v);size[u]+=size[v];
		if(!son[u]||size[v]>size[son[u]]) son[u]=v;
	}
	return;
}
void dfs(int u,int t){
	top[u]=t;id[u]=++I,dfn[I]=u;
	if(!son[u]) return;
	dfs(son[u],t);
	for(int v,i=head[u];i;i=a[i].next) if((v=a[i].to)==son[u]||v==fa[u]) continue;else dfs(v,v);
	return;
}
ll Sum[N],SR[N];
const int MAXN=N*100;
int ls[MAXN],rs[MAXN],vis[MAXN],rt[N];
ll E[MAXN];int F[MAXN];int cur=0,NOW=0;
void Build(int &u,int l,int r){
	u=++cur;E[u]=F[u]=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	Build(ls[u],l,mid);Build(rs[u],mid+1,r);
	return;
}
void Modify(int&u,int l,int r,int L,int R){
	if(L>R) return;
	int p=u;
	if(vis[p]!=NOW) {p=++cur;
		ls[p]=ls[u],rs[p]=rs[u];
		E[p]=E[u],F[p]=F[u];vis[p]=NOW;
		u=p;
	}E[p]+=SR[R]-SR[L-1];
	if(l>=L&&r<=R) {++F[p];return;}
	int mid=l+r>>1;
	if(mid>=R) return Modify(ls[p],l,mid,L,R);
	if(mid< L) return Modify(rs[p],mid+1,r,L,R);
	Modify(ls[p],l,mid,L,mid);Modify(rs[p],mid+1,r,mid+1,R);
	return;
}
inline void Modify(int &rt,int u){
	++NOW;
	while(top[u]) {Modify(rt,1,n,id[top[u]],id[u]);u=fa[top[u]];}
	return;
}
void Query(int v,int u,int l,int r,int L,int R,ll&ans){
	if(L>R) return;
	if(!u&&!v) return;
	if(l>=L&&r<=R) {ans+=E[u]-E[v];return;}
	ans+=(SR[R]-SR[L-1])*(F[u]-F[v]);
	int mid=l+r>>1;
	if(mid>=R) return Query(ls[v],ls[u],l,mid,L,R,ans);
	if(mid< L) return Query(rs[v],rs[u],mid+1,r,L,R,ans);
	return Query(ls[v],ls[u],l,mid,L,mid,ans),Query(rs[v],rs[u],mid+1,r,mid+1,R,ans);
}
inline ll Query(int l,int r,int u){
	ll res=0;
	while(top[u]) Query(rt[l],rt[r],1,n,id[top[u]],id[u],res),u=fa[top[u]];
	return res;
}
void work(){
	int lst=0;
	Dfs(1),dfs(1,1);
	for(int i=1;i<=n;++i) SR[i]=SR[i-1]+Ret[dfn[i]];
	Build(rt[0],1,n);
	for(int i=1;i<=n;++i) Sum[i]=Sum[i-1]+dis[LISAN::id[i]],rt[i]=rt[i-1],Modify(rt[i],LISAN::id[i]);
	for(int i=1;i<=m;++i) {
		int l,r,x;init(x),init(l),init(r);
		l=(l+lst)%LIM,r=(r+lst)%LIM;
		if(l>r) swap(l,r);
		l=Lower(l);r=Lower(r+1)-1;ll ans=0;
		ans=Query(l-1,r,x);
		ans=(Sum[r]-Sum[l-1])+(ll)(r-l+1)*dis[x]-(ans<<1);
		printf("%lld\n",ans);
		lst=ans%LIM;
	}
}
int main()
{
	init(n),init(m),init(LIM);
	LISAN::Prepare();
	int u,v,w;
	for(int i=1;i<n;++i) {init(u),init(v),init(w);add(u,v,w);add(v,u,w);}
	work();
	return 0;
}
【LuoguP3241】[HNOI2015] 开店的更多相关文章
- [HNOI2015]开店 树链剖分,主席树
		[HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ... 
- 洛谷 P3241 [HNOI2015]开店 解题报告
		P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ... 
- [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)
		4012: [HNOI2015]开店 Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 2168 Solved: 947[Submit][Status] ... 
- 【BZOJ4012】[HNOI2015]开店 动态树分治+二分
		[BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ... 
- BZOJ4012 [HNOI2015]开店
		Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ... 
- bzoj 4012: [HNOI2015]开店
		Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ... 
- bzoj 4012: [HNOI2015]开店 主席树
		Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ... 
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
		题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ... 
- BZOJ4012: [HNOI2015]开店【动态点分治】
		Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ... 
随机推荐
- C# 图片文件文本string格式 传输问题
			string file = @"E:\test.png"; byte[] bytes = File.ReadAllBytes(file); // 主要代码 string datas ... 
- 测开之路一百五十五:jquery-validation前台数据验证
			前面做的wtform验证是服务器端的验证,需要把数据传输到服务器,服务器验证后再吧结果传输到前端,网络慢的时候,用户体验不好,所以需要前端验证,且后端验证不能少 传统的js或者jquery如果要验证信 ... 
- Linux下安装Elasticsearch6.5
			1.安装JDK8(Elastic 需要 Java 8 环境) 1)下载jdk8文件:http://www.oracle.com/technetwork/java/javase/downloads/jd ... 
- 【MM系列】SAP MR21修改标准价
			公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]在SAP里查看数据的方法 前言部 ... 
- Java多线程学习——知识点积累
			开启多线程时,每一个线程都拥有自己的工作空间,每个工作空间都单独的和主存打交道. 并发的概念:多个线程同时操作同一个对象 当产生并发时,如果从工作空间写入数据到内存的线程时间片用完了,其他线程再从主存 ... 
- 用seaborn对数据可视化
			以下用sns作为seaborn的别名 1.seaborn整体布局设置 sns.set_syle()函数设置图的风格,传入的参数可以是"darkgrid", "whiteg ... 
- MySQL的count(*)性能怎么样?
			对于count(主键id)来说,innodb引擎会遍历整张表,把每一行的id值都取出来,返回给server层,server层判断id值不为空,就按行累加 对于count(1)来说,innodb引擎遍历 ... 
- poj-1236.network of schools(强连通分量 + 图的入度出度)
			Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 27121 Accepted: 10 ... 
- XLS导出的服务器端配置方式
			IIS支持excel导出: 1.开始—运行,然后键入DCOMCNFG; 2.组件服务—计算机—我的电脑—DCOM配置,这时弹出一个问注册的窗口,确定注册. 这时如果一切恢复正常了,不用往下操作了. 关 ... 
- 安装开发环境vs2017+sql2016+tfs2017
			安装开发环境vs2017+sql2016+tfs2017 编写人:左丘文 2019-7-16 近一年了,一直没空着手写点什么,跟大家交待下吧,去年一次机会,其实也不完全是去年,因此离开了我工作15年的 ... 
