BZOJ4012 [HNOI2015]开店 (动态点分治)
Description
风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到
Input
第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖
Output
对于每个方案,输出一行表示方便值。
Sample Input
0 0 7 2 1 4 7 7 7 9
1 2 270
2 3 217
1 4 326
2 5 361
4 6 116
3 7 38
1 8 800
6 9 210
7 10 278
8 9 8
2 8 0
9 3 1
8 0 8
4 2 7
9 7 3
4 7 0
2 2 7
3 2 1
2 3 4
Sample Output
957
7161
9466
3232
5223
1879
1669
1282
0
HINT
满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9
题解
这题正解是动态点分治(不过据说主席树+树链剖分跑得更快?)
如果不知道什么是动态点分的可以去看看幻想乡的战略游戏->蒟蒻的题解
这一道题,我们考虑对于每一个点分树上的点维护什么。我们记录三个值,$sz_0$表示子树内的点数之和,$sz_1$表示子树内所有点到其的距离之和,$sz_2$表示子树内所有点到其父亲的距离之和。那么考虑我们在跳点分树的时候要如何维护答案呢?很明显$sz_1[u]+\sum sz_1[fa]-sz_2[p]+(sz_0[fa]-sz_0[p])*dist(fa,u)$就是在点分树上与$u$的$LCA$是$fa$的所有点的距离之和,其中$fa$为$p$的父亲,$p$为从$u$不断跳父亲直到根,那么只要不断枚举$fa$,并不断往上跳并维护答案就可以了。
然而上面只是为了方便理解,因为具体的计算不是这样的。我们对于$u$点内部的贡献可以直接计算,然后考虑往上跳。在上述的式子中如果一个点$p$有$fa$,那么答案就要减去$sz_0[p]*dist(fa,u)+sz_2[p]$,如果一个点不是$u$那么答案就要加上$sz_0[p]+dist(p,u)$,然后每一个点都要加上自己的$sz_1$。按这个规律在跳点分树的时候不断加就好了
然后考虑怎么在$[l,r]$之内,很明显可以搞一个差分,把每一个节点在点分树上的子树内的所有年龄的距离之和加起来,在做前缀和,那么在年龄$[l,r]$的人数就是$[1,r]-[1,l-1]$
//minamoto
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#define ll long long
#define N 150005
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
int head[N],Next[N<<],ver[N<<],edge[N<<];
int n,tot,val[N],q,maxn;
int st[N<<][],d[N],dfn[N],num,bin[],tp,logn[N<<];
inline void add(int u,int v,int e){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=e;
}
inline void ST(){
for(int j=;j<=tp;++j)
for(int i=;i+bin[j]-<=(n<<);++i)
st[i][j]=min(st[i][j-],st[i+bin[j-]][j-]);
}
void dfs1(int u,int fa){
st[dfn[u]=++num][]=d[u];
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v==fa) continue;
d[v]=d[u]+edge[i],dfs1(v,u),st[++num][]=d[u];
}
}
int fa[N],sz[N],son[N],size,rt;bool vis[N];
void dfs2(int u,int fa){
sz[u]=,son[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]||v==fa) continue;
dfs2(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]);
}
cmax(son[u],size-sz[u]);
if(son[u]<son[rt]) rt=u;
}
inline ll dis(int a,int b){
if(dfn[a]>dfn[b]) a^=b^=a^=b;
int k=logn[dfn[b]-dfn[a]+];
return d[a]+d[b]-(min(st[dfn[a]][k],st[dfn[b]-bin[k]+][k])<<);
}
struct node{
int val;ll sz[];
node(int a=,ll b=,ll c=,ll d=){val=a,sz[]=b,sz[]=c,sz[]=d;}
inline bool operator <(const node &b)const
{return val<b.val;}
};
vector<node> sta[N];
void dfs3(int u,int f,int rt){
sta[rt].push_back(node(val[u],,dis(u,rt),fa[rt]?dis(u,fa[rt]):));
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v==f||vis[v]) continue;
dfs3(v,u,rt);
}
}
void dfs4(int u){
vis[u]=true;
dfs3(u,,u);sta[u].push_back(node(-,,,));
sort(sta[u].begin(),sta[u].end());
for(int i=,j=sta[u].size();i<j-;++i)
sta[u][i+].sz[]+=sta[u][i].sz[],
sta[u][i+].sz[]+=sta[u][i].sz[],
sta[u][i+].sz[]+=sta[u][i].sz[];
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]) continue;
rt=,size=sz[v];
dfs2(v,),fa[rt]=u,dfs4(rt);
}
}
inline node query(int id,int l,int r){
if(id==) return node();
vector<node>::iterator it1=upper_bound(sta[id].begin(),sta[id].end(),node(r,,,));--it1;
vector<node>::iterator it2=upper_bound(sta[id].begin(),sta[id].end(),node(l-,,,));--it2;
return node(,it1->sz[]-it2->sz[],it1->sz[]-it2->sz[],it1->sz[]-it2->sz[]);
}
inline ll calc(int u,int l,int r){
ll res=;
for(int p=u;p;p=fa[p]){
node a=query(p,l,r);
res+=a.sz[];
if(p!=u) res+=a.sz[]*dis(p,u);
if(fa[p]) res-=a.sz[]+a.sz[]*dis(fa[p],u);
}
return res;
}
int main(){
ll ans=;
n=read(),q=read(),maxn=read();
bin[]=,logn[]=-;
for(int i=;i<=;++i) bin[i]=bin[i-]<<;
while(bin[tp+]<=(n<<)) ++tp;
for(int i=;i<=(n<<);++i) logn[i]=logn[i>>]+;
for(int i=;i<=n;++i) val[i]=read();
for(int i=;i<n;++i){
int u=read(),v=read(),e=read();
add(u,v,e);
}
dfs1(,),ST();
rt=,son[]=n+,size=n,dfs2(,);
dfs4(rt);
while(q--){
int a=read(),b=read(),c=read();
b=(b+ans)%maxn,c=(c+ans)%maxn;
if(b>c) b^=c^=b^=c;
print(ans=calc(a,b,c));
}
Ot();
return ;
}
BZOJ4012 [HNOI2015]开店 (动态点分治)的更多相关文章
- [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)
4012: [HNOI2015]开店 Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 2168 Solved: 947[Submit][Status] ...
- 【bzoj4012】[HNOI2015]开店 动态点分治+STL-vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题 ...
- 【BZOJ4012】[HNOI2015]开店 动态树分治+二分
[BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...
- P3241 [HNOI2015]开店 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
- luogu 3241 [HNOI2015]开店 动态点分治+二分+vector
独立写出来+想出来的,1.5h就切了~ 建立点分树,然后用 $vector$ 暴力存所有子节点,然后二分一下子就可以了. #include <cstdio> #include <ve ...
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- BZOJ4012: [HNOI2015]开店【动态点分治】
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
- [loj2116]「HNOI2015」开店 动态点分治
4012: [HNOI2015]开店 Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 2452 Solved: 1089[Submit][Status ...
- BZOJ4012 [HNOI2015]开店
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
随机推荐
- HDFS NameNode HA 部署文档
简介: HDFS High Availability Using the Quorum Journal Manager Hadoop 2.x 中,HDFS 组件有三个角色:NameNode.DataN ...
- 使用ES-Hadoop 6.5.4编写MR将数据索引到ES
目录 1. 开发环境 2. 下载地址 3. 使用示例 4. 参考文献 1. 开发环境 Elasticsearch 6.5.4 ES-Hadoop 6.5.4 Hadoop 2.0.0 2. 下载地址 ...
- js中元素结点的引用
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Redis 基础操作
[Redis 基础操作] 1.ECHO message. Returns message. 2.PHING Returns PONG if no argument is provided, other ...
- cmake 查看配置选项
cmake 查看配置选项可以用如下命令 cmake . -LH 查看help > cmake -h cmake version 2.6-patch 4 Usage cmake [optio ...
- 宽字符、多字节、unicode、utf-8、gbk编码转化
今天遇到一个编码的问题,困惑了我很长时间,所以就简要的的了解了一下常用的编码类型. 我们最常见的是assic编码,它是一种单字节编码,对多容纳256个字符. 我们在编程的时候经常遇到unicode,u ...
- win10 跳过max path 260限制
参考: https://www.howtogeek.com/266621/how-to-make-windows-10-accept-file-paths-over-260-characters/ 注 ...
- TF Boys (TensorFlow Boys ) 养成记(六): CIFAR10 Train 和 TensorBoard 简介
圣诞节玩的有点嗨,差点忘记更新.祝大家昨天圣诞节快乐,再过几天元旦节快乐. 来继续学习,在/home/your_name/TensorFlow/cifar10/ 下新建文件夹cifar10_train ...
- JavaScript 语法总结3
1. 数组初始化可以跳着来 var s = [1,2,,,,6]; // 中间省略的元素为undefined 2. 函数定义表达式: var f = function(args){ return ...
- Zookeeper客户端cli_st为何在crontab中运行不正常?
实践中,发现直接在命令行终端运行cli_st时,能够得到预期的结果,但一将它放到crontab中,则只收到: bye 相关的一段clit_st源代码如下: if (FD_ISSET(, &rf ...