BZOJ 4012 【HNOI2015】 开店

题目链接:开店

  这道题显然一眼树分治,维护点分的结构,在每个点上,对每种年龄到这个点\(u\)以及他在点分树上父亲的距离和建一棵主席树,查询的时候一路往上跳即可。

  但是我太懒了(其实你要说我不会也可以),所以并不想写这种东西。于是,我就只能尝试一下别的方法。

  设一个点\(u\)的年龄为\(y_u\),\(u\)、\(v\)两点之间的距离为\(dis(u,v)\),\(T_u=dis(root,u)\),我们每次要求的式子是:

\begin{aligned} &\sum_{y_x\in [l,r]} dis(y,u)\\ =&\sum_{y_x\in [l,r]}(T_y+T_u-2T_{LCA(u,v)})\end{aligned}

  注意到前面那两项我们是可以通过预处理前缀和\(O(1)\)求出的。于是我们就只需要考虑后面那坨东西怎么求。

  我们可以考虑转化一下思路,转而求每条边的贡献。我们考虑对于一个点\(x\)满足\(y_x\in[l,r]\),那么\(LCA(u,x)\)一直到根的路径都要被计算一次。那么我们就可以对于每个\(y_x\in[l,r]\),把点\(x\)往上跳,途中经过的边标记加\(1\)。那么最后我们再从\(u\)往上跳,每条边的的标记数就是这条边被计算的次数。那么我们就只需要快速维护一个点到根的路径即可。这个可以树链剖分之后用权值线段树解决。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 150010
#define MAXN 6000010
#define point pair<int,int>
#define sa first
#define sb second

using namespace std;
typedef long long llg;

point s[maxn];
int n,Q,A,a[maxn],da[maxn],ld,dep[maxn],c1[maxn];//c1[x]表示[1,x]出现的次数和
int head[maxn],next[maxn<<1],to[maxn<<1],c[maxn<<1],tt;//邻接表
int fa[maxn],top[maxn],siz[maxn],son[maxn],tc[maxn],wd[maxn],fd[maxn];//树链剖分
int rt[maxn],addv[MAXN],le[MAXN],ri[MAXN],L,R,CO,_1,_2;//主席树
llg ans,c2[maxn],sumv[MAXN],ji;//c2[x]表示∑dep[u](a[u]∈[1,x])

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar();
	if(c==‘-‘) c=getchar(),q=1;
	while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar();
	return q?-w:w;
}

void link(int x,int y){
	to[++tt]=y;next[tt]=head[x];head[x]=tt;
	to[++tt]=x;next[tt]=head[y];head[y]=tt;
	c[tt]=c[tt-1]=getint();
}

void dfs(int u){
	siz[u]=1; c1[a[u]]++; c2[a[u]]+=dep[u];
	for(int i=head[u],v;v=to[i],i;i=next[i])
		if(!siz[v]){
			dep[v]=dep[u]+c[i];
			fa[v]=u; dfs(v); siz[u]+=siz[v];
			if(siz[v]>siz[son[u]]) son[u]=v;
		}
}

void dfs(int u,int ot){
	top[u]=ot; tc[u]=++tt;
	wd[tt]=dep[u]; fd[tt]=dep[fa[u]];
	if(son[u]) dfs(son[u],ot);
	for(int i=head[u],v;v=to[i],i;i=next[i])
		if(!top[v]) dfs(v,v);
}

void add(int &u,int l,int r){
	tt++; addv[tt]=addv[u];
	le[tt]=le[u],ri[tt]=ri[u];
	sumv[tt]=sumv[u]; u=tt;
	int mid=(l+r)>>1;
	if(l>=L && r<=R){
		sumv[u]+=wd[r]-fd[l];
		addv[u]++; return;
	}
	if(L<=mid) add(le[u],l,mid);
	if(R>mid) add(ri[u],mid+1,r);
	sumv[u]=sumv[le[u]]+sumv[ri[u]];
	sumv[u]+=(llg)addv[u]*(wd[r]-fd[l]);
}

void work(int u,int co){
	while(u){
		L=tc[top[u]],R=tc[u];
		add(rt[co],1,n); u=fa[top[u]];
	}
}

void query(int u1,int u2,int l,int r){
	int mid=(l+r)>>1;
	if(l>=L && r<=R){
		ji+=sumv[u2]+(llg)_2*(wd[r]-fd[l]);
		ji-=sumv[u1]+(llg)_1*(wd[r]-fd[l]);
		return;
	}
	_1+=addv[u1]; _2+=addv[u2];
	if(L<=mid) query(le[u1],le[u2],l,mid);
	if(R>mid) query(ri[u1],ri[u2],mid+1,r);
	_1-=addv[u1]; _2-=addv[u2];
}

int up(int x){//二分>=x的第一个
	int l=1,r=ld,mid;
	while(l!=r){
		mid=(l+r)>>1;
		if(da[mid]>=x) r=mid;
		else l=mid+1;
	}
	return l;
}

int lo(int x){//二分<=x的第一个
	int l=1,r=ld,mid;
	while(l!=r){
		mid=(l+r+1)>>1;
		if(da[mid]<=x) l=mid;
		else r=mid-1;
	}
	return l;
}

int main(){
	File("shop");
	n=getint(); Q=getint(); A=getint(); ld=n;
	for(int i=1;i<=n;i++) a[i]=da[i]=getint(); da[++ld]=A+1;
	sort(da+1,da+ld+1); ld=unique(da+1,da+ld+1)-da-1;
	for(int i=1;i<=n;i++) a[i]=up(a[i]),s[i]=make_pair(a[i],i);
	for(int i=1;i<n;i++) link(getint(),getint());
	tt=0; dfs(1); dfs(1,1); sort(s+1,s+n+1); tt=0;
	for(int i=1;i<=ld;i++) c1[i]+=c1[i-1],c2[i]+=c2[i-1];
	for(int i=1;i<=n;i++){
		if(s[i].sa!=s[i-1].sa) rt[s[i].sa]=rt[s[i-1].sa];
		CO=s[i].sa; work(s[i].sb,s[i].sa);
	}
	rt[ld]=rt[ld-1];
	while(Q--){
		int u=getint(),aa=getint(),bb=getint(),l,r; ji=0;
		(aa+=ans%A)%=A; (bb+=ans%A)%=A;
		l=min(aa,bb),r=max(aa,bb); l=up(l); r=lo(r);
		if(l>r) ans=ji=0;
		else{
			ans=c2[r]-c2[l-1]+(llg)(c1[r]-c1[l-1])*dep[u];
			while(u){
				L=tc[top[u]],R=tc[u];
				query(rt[l-1],rt[r],1,n);
				u=fa[top[u]];
			}
			ans-=ji<<1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
时间: 2024-10-10 00:39:49

BZOJ 4012 【HNOI2015】 开店的相关文章

[BZOJ 4012][HNOI2015]开店(树链剖分+主席树)

Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这

BZOJ 4012 HNOI2015 开店 树的边分治

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权值,现在有Q组询问,每组给出信息u,L,R,问点权在区间[L,R]的点到点u的距离和为多少.强制在线. N<=150000,Q<=200000. 可能这是我这几天做过的题里面最水但是最码的一个了.... 实际上看见树上所有点的度不超过3就感觉可以用边分治做,具体的思路实际上很简单,建立一个边分治结

BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和,强制在线 没记错的话这题我知道的有三种解法来着? (茴香豆的茴有四种写法泥萌知道嘛-? 1.线段树维护虚树 2.点分治+线段树 3.分块 第一种方法我不知道在线怎么搞= = (我并不知道怎么在虚树上进行点定位 第三种方法貌似内存过不去? 于是果断点分治+线段树 写完发现内存还是炸了= = O(nlog2n)的内存说什么也过不去啊= = 后来发现既然维护的是和不是最值那还要线段树干嘛= = 直接开

[BZOJ4012][HNOI2015]开店(动态点分治)

4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status][Discuss] Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面 向什么样的人群.很神奇的是,幻想乡的地

BZOJ 4008: [HNOI2015]亚瑟王( dp )

dp(i, j)表示考虑了前i张牌, 然后还有j轮的概率. 考虑第i+1张牌: 发动的概率 : p = dp(i, j) * (1 - (1-p[i+1])^j) 没发动的概率 : dp(i, j) * (1 - p[i+1])^j 分别转移到状态: dp(i+1, j-1) dp(i+1, j) 同时假如i+1发动了对答案还有贡献p*d(i+1) 时间复杂度O(NTR) (好像有点不和谐..... ------------------------------------------------

BZOJ4012 [HNOI2015]开店

首先这个叫"动态点分治",不过瞎YY也能YY出来[比如我... 就是记录下点分治的过程和每个点的答案信息,于是查询的时候只要沿着分治好的根一路走下去就行了,于是单次查询的外层复杂度是$O(log n)$的 对于每个点,要记录以从整棵树到它的分治路径和以它为根的子树内权值小于v的点到它的距离和(就是关于权值的前缀和) 于是查询一个点的时候只要二分一下就好了... 总复杂度$O((n + Q) * log^2n)$ 写了一晚上QAQQQ 1 /***********************

bzoj 4010: [HNOI2015]菜肴制作 拓扑排序

4010: [HNOI2015]菜肴制作 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/67 Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予 1到N的顺序编号,预估质量最高的菜肴编号为1.由于菜肴之间口味搭配的问题, 某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M 条形如“i 号菜肴‘必须’

BZOJ 4011: [HNOI2015]落忆枫音( dp )

DAG上有个环, 先按DAG计数(所有节点入度的乘积), 然后再减去按拓扑序dp求出的不合法方案数(形成环的方案数). -------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long l

BZOJ 4009: [HNOI2015]接水果

4009: [HNOI2015]接水果 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 636  Solved: 300[Submit][Status][Discuss] Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更 加难的版本.首先有一个地图,是一棵由 n 个顶点.n-1 条边组成的树(例如图