P3241 [HNOI2015]开店
时间:2020-04-20
本文章向大家介绍P3241 [HNOI2015]开店,主要包括P3241 [HNOI2015]开店使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
这里是一种动态点分治的解法(不过听说树剖+主席树更快?)。
首先先考虑除去年龄的限制这道题怎么做。也就是给你一棵树,每次询问一个点到所有其他点的距离和。
由于路径问题不太关系树的形态,并且问的又是一个点和整棵树之间的关系,所以可以考虑动态点分治:
- 每个点保存它在点分树内的子树的信息
- 设\(dis1[i]\)表示\(i\)子树内所有点到它的距离之和,\(dis2[i]\)表示\(i\)子树内所有点到\(fa[i]\)(依然是点分树上的父亲)的距离
- 查询就直接跳点分树好了
现在带上年龄的限制,我们依然可以“每个点保存它在点分树内的子树的信息”,我们可以用一个\(vector\)把一棵子树里的点全部保存下来,按年龄拍个序,求一下\(dis1\)和\(dis2\)的后(前)缀和,最后询问的时候二分一下就好了。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int N=500009,INF=1<<30;
int n,Q,age[N],log[N],A,head[N],cnt,F[N],root,R[N],L[N],Index,DFN[N],rev[N];
struct D
{
LL dis1,dis2;
int age;
bool operator < (const D &A)const
{
return age<A.age;
}
};
vector <D> b[N];
struct Edge
{
int nxt,to;
}g[N*2];
struct G
{
int head[N],cnt,Euler[N],Index,Fst[N],f[N][30],dep[N],siz[N],del[N];
LL dis[N];
struct Edge
{
int nxt,to,w;
}g[N*2];
void add(int from,int to,int w)
{
g[++cnt].nxt=head[from];
g[cnt].to=to;
g[cnt].w=w;
head[from]=cnt;
}
void dfs(int x,int fa)
{
Euler[++Index]=x,f[Index][0]=x,Fst[x]=Index;
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa)
continue;
dep[v]=dep[x]+1,dis[v]=dis[x]+g[i].w;
dfs(v,x);
Euler[++Index]=x,f[Index][0]=x;
}
}
int LCA(int x,int y)
{
if(Fst[x]>Fst[y])
swap(x,y);
x=Fst[x],y=Fst[y];
int k=log[y-x+1];
return dep[f[x][k]]<dep[f[y-(1<<k)+1][k]]?f[x][k]:f[y-(1<<k)+1][k];
}
LL Get_Dis(int x,int y)
{
return dis[x]+dis[y]-2*dis[LCA(x,y)];
}
void DFS(int x,int fa)
{
siz[x]=1;
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa||del[v])
continue;
DFS(v,x);
siz[x]+=siz[v];
}
}
int Get_Weight(int x)
{
DFS(x,-1);
int k=siz[x]/2,fa=-1;
while(1)
{
int tmp=0;
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa||del[v])
continue;
if(siz[tmp]<siz[v])
tmp=v;
}
if(siz[tmp]<=k)
return x;
fa=x,x=tmp;
}
}
void work()
{
dfs(1,-1);
for (int j=1;1<<j<=Index;j++)
for (int i=1;i+(1<<j)<=Index;i++)
if(dep[f[i][j-1]]<dep[f[i+(1<<j-1)][j-1]])
f[i][j]=f[i][j-1];
else
f[i][j]=f[i+(1<<j-1)][j-1];
}
}T;
void add(int from,int to)
{
g[++cnt].nxt=head[from];
g[cnt].to=to;
head[from]=cnt;
}
void init()
{
log[0]=-1;
for (int i=1;i<=N-9;i++)
log[i]=log[i>>1]+1;
scanf("%d %d %d",&n,&Q,&A);
for (int i=1;i<=n;i++)
scanf("%d",&age[i]);
for (int i=1;i<n;i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
T.add(x,y,z),T.add(y,x,z);
}
T.work();
}
void build(int fa)
{
T.del[fa]=1,DFN[fa]=++Index,L[fa]=Index,rev[Index]=fa;
for (int i=T.head[fa];i;i=T.g[i].nxt)
{
int v=T.g[i].to;
if(v==fa||T.del[v])
continue;
int w=T.Get_Weight(v);
F[w]=fa,add(fa,w),add(w,fa);
build(w);
}
R[fa]=Index;
//printf("%d %d %d\n",fa,L[fa],R[fa]);
}
void print(int x,int fa)
{
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa)
continue;
printf("%d %d\n",x,v);
print(v,x);
}
}
void dfs(int x,int fa)
{
b[x].push_back((D){0,fa!=-1?T.Get_Dis(fa,x):0,age[x]});
b[x].push_back((D){0,0,INF});
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa)
continue;
for (int j=L[v];j<=R[v];j++)
{
int J=rev[j];
b[x].push_back( ( D ) { T.Get_Dis(x,J) , fa!=-1?T.Get_Dis(fa,J):0 , age[J] } );
}
dfs(v,x);
}
sort(b[x].begin(),b[x].end());
for (int i=b[x].size()-2;i>=0;i--)
b[x][i].dis1+=b[x][i+1].dis1,b[x][i].dis2+=b[x][i+1].dis2;
//printf("now_%d\n",x);
//for (int i=0;i<b[x].size();i++)
//printf("%d ",b[x][i].age);puts("");
}
LL Query(int x,int l,int r)
{
vector <D> ::iterator L,R;
LL ans=0;
for (int i=x;i;i=F[i])
{
L=lower_bound(b[i].begin(),b[i].end(),(D){0,0,l});
R=upper_bound(b[i].begin(),b[i].end(),(D){0,0,r});
ans+=(L->dis1-R->dis1)+1LL*(R-L)*T.Get_Dis(x,i);
if(F[i])
ans-=1LL*(R-L)*T.Get_Dis(x,F[i])+L->dis2-R->dis2;
}
return ans;
}
void work()
{
root=T.Get_Weight(1);
//puts("pipi");
build(root);
//puts("houhou");
//print(root,-1);
dfs(root,-1);
LL last=0;
for (int _=1;_<=Q;_++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
int L=min((y+last)%A,(z+last)%A),R=max((y+last)%A,(z+last)%A);
if(L>R)
swap(L,R);
//printf("L=%d R=%d\n",L,R);
printf("%lld\n",last=Query(x,L,R));
}
}
int main()
{
init();
work();
return 0;
}
原文地址:https://www.cnblogs.com/With-penguin/p/12735034.html
- 自己写个 Prisma
- Numpy|需要信手拈来的功能
- 数据库连接池极简教程
- 碎片化 | 第四阶段-35-Struts2-Spring结合jdbc实现查询列表-视频
- 碎片化 | 第四阶段-28-Struts2框架概述以及原理图解-视频
- nginx 负载均衡
- 机器学习算法应用中常用技巧-1
- 碎片化 | 第四阶段-29-Struts2入门示例1-视频
- nginx虚拟主机配置
- nginx rewrite
- 碎片化 | 第四阶段-30-Struts2入门示例流程梳理-视频
- 碎片化 | 第一阶段-01-基本常识-视频
- 你真的了解For循环吗?一道For循环Java面试题引发的思考
- 碎片化 | 第一阶段-02-Java的跨平台性-视频
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于Python爬取fofa网页端数据过程解析
- Python logging日志模块 配置文件方式
- PHP XML Expat解析器知识点总结
- PHP实现唤起微信支付功能
- PHP封装的mysqli数据库操作类示例
- PHP-FPM 的管理和配置详解
- PHP基于curl实现模拟微信浏览器打开微信链接的方法示例
- 实例讲解PHP表单验证功能
- python如何从键盘获取输入实例
- 使用Keras实现Tensor的相乘和相加代码
- php无限级分类实现评论及回复功能
- php获取手机端的号码以及ip地址实例代码
- PHP数组遍历的几种常见方式总结
- 详解php协程知识点
- php curl简单采集图片生成base64编码(并附curl函数参数说明)