LOJ2116 [HNOI2015] 开店 【点分治】
题目分析:
观察题目发现度数不小于三,考虑从边分治入手,用点分治代替。将树划分成重心链接的结构,称为点分树。令当前询问的点为$ u $。那么我们考虑点分树的根到$ u $的一条路径。考虑根结点,排除掉与$ u $有关的点所在的子树,剩下的点到$ u $的路径长度等价于它们到根的路径加上根到$ u $的路径。所以我们要做的是消去$ u $所在子树的影响,然后递归问题。这个做法在点分治意义下是常用做法,前缀和维护即可。由于每个点都在点分路径上的前缀和上出现了一次,而点分树高为$ O(\log n) $,所以空间为$ O(n*\log n) $。时间是$ O(n*\log^2n) $
代码:
#include<bits/stdc++.h>
using namespace std; const int maxn = ; int n,Q,A; int x[maxn]; vector <pair<int,int> > g[maxn];
int euler[maxn<<],nE,app[maxn][];
int RMQ[maxn<<][],f[maxn],dep[maxn],climb[maxn]; template<typename T>
void in(T &x){
x = ; char ch = getchar();
while(ch > '' || ch < '') ch = getchar();
while(ch >= '' && ch <= '') x = x*+ch-'',ch=getchar();
} void dfs(int now,int last,int dp,int cl){
dep[now] = dp; f[now] = last; climb[now] = cl;
euler[++nE] = now; app[now][] = app[now][] = nE;
for(int i=;i<g[now].size();i++){
int pp = g[now][i].first,len = g[now][i].second;
if(pp == last) continue;
dfs(pp,now,dp+len,cl+);
euler[++nE] = now; app[now][] = nE;
}
} void BuildRMQ(){
for(int i=;i<=nE;i++) RMQ[i][] = euler[i];
for(int k=;(<<k)<=nE;k++){
for(int i=;i<=nE;i++){
if(i+(<<k-) > nE) {RMQ[i][k] = RMQ[i][k-];continue;}
if(climb[RMQ[i][k-]] < climb[RMQ[i+(<<k-)][k-]]){
RMQ[i][k] = RMQ[i][k-];
}else RMQ[i][k] = RMQ[i+(<<k-)][k-];
}
}
} int QueryLCA(int u,int v){
int fst = min(app[u][],app[v][]),sec = max(app[u][],app[v][]);
int len = sec-fst+,k = ;
while((<<k+) <= len) k++;
if(climb[RMQ[fst][k]] < climb[RMQ[sec-(<<k)+][k]]) return RMQ[fst][k];
else return RMQ[sec-(<<k)+][k];
} int dist(int u,int v){ return dep[u]+dep[v]-*dep[QueryLCA(u,v)]; } class Pdivide{
private:
int sz[maxn],arr[maxn],seg[maxn],fa[maxn];
vector <pair<int,int> > v[maxn],v2[maxn];
vector <long long> sum[maxn],sum2[maxn];
stack <int> sta;
void GetSize(int now,int last){
sz[now] = ;seg[now] = ;
for(int i=;i<g[now].size();i++){
int pp = g[now][i].first;
if(arr[pp] || pp == last) continue;
GetSize(pp,now);
sz[now] += sz[pp];
seg[now] = max(seg[now],sz[pp]);
}
sz[now]++;
}
int GetG(int now,int last,int tot){
int res = now; seg[now] = max(seg[now],tot-sz[now]-);
for(int i=;i<g[now].size();i++){
int pp = g[now][i].first;
if(arr[pp] || pp == last) continue;
int p = GetG(pp,now,tot);
if(seg[p] < seg[res]) res = p;
}
return res;
}
void LenQuery(int now,int last,int dst,int root,int oldroot){
v[root].push_back(make_pair(x[now],dst));
if(oldroot != ) v2[root].push_back(make_pair(x[now],dist(now,oldroot)));
for(int i=;i<g[now].size();i++){
int pp = g[now][i].first, len = g[now][i].second;
if(arr[pp] || pp == last) continue;
LenQuery(pp,now,dst+len,root,oldroot);
}
}
void divide(int now,int last,int ht){
GetSize(now,);
int p = GetG(now,,sz[now]); LenQuery(p,,,p,last); sort(v[p].begin(),v[p].end()); sum[p].push_back();
sort(v2[p].begin(),v2[p].end()); sum2[p].push_back();
for(int i=;i<v[p].size();i++) sum[p].push_back(sum[p][i]+1ll*v[p][i].second);
for(int i=;i<v2[p].size();i++) sum2[p].push_back(sum2[p][i]+1ll*v2[p][i].second); fa[p] = last;arr[p] = ht;
for(int i=;i<g[p].size();i++){
int nxt = g[p][i].first;
if(arr[nxt]) continue;
divide(nxt,p,ht+);
}
} public:
void BuildTree(){divide(,,);}
void printans(int now,int l,int r,long long &lastans){
int p = now;
while(p != ) sta.push(p),p = fa[p];
long long ans = ;
while(!sta.empty()){
int tp = sta.top();sta.pop();
int pp = lower_bound(v[tp].begin(),v[tp].end(),make_pair(l,))-v[tp].begin();
if(pp == v[tp].size()||v[tp][pp].first > r) break;
int ed = upper_bound(v[tp].begin(),v[tp].end(),make_pair(r,(int)1E9))-v[tp].begin()-;
int len = ed-pp+;
ans += sum[tp][ed+] - sum[tp][pp] + 1ll*len*dist(tp,now);
if(fa[tp]!=)
ans -= (sum2[tp][ed+] - sum2[tp][pp] + 1ll*len*dist(fa[tp],now));
}
while(!sta.empty())sta.pop();
printf("%lld\n",ans);lastans = ans;
}
}T1; void init(){
dfs(,,,);
BuildRMQ();
T1.BuildTree();
} void work(){
long long lastans = ;
for(int i=;i<=Q;i++){
int a,u,v; in(a),in(u),in(v);
u = (1ll*u+lastans)%A;
v = (1ll*v+lastans)%A;
if(u > v) swap(u,v);
T1.printans(a,u,v,lastans);
}
} int main(){
in(n),in(Q),in(A);
for(int i=;i<=n;i++) in(x[i]);
for(int i=;i<n;i++){
int u,v,w; in(u),in(v),in(w);
g[u].push_back(make_pair(v,w));
g[v].push_back(make_pair(u,w));
}
init();
work();
return ;
}
LOJ2116 [HNOI2015] 开店 【点分治】的更多相关文章
- BZOJ 4012 [HNOI2015]开店 (树分治+二分)
题目大意: 给你一棵树,边有边权,点有点权,有很多次询问,求点权$\in[l,r]$的所有节点到某点$x$的距离之和,强制在线 感觉这个题应该放在动态点分之前做= = 套路方法和动态点分是一样的 每次 ...
- [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)
4012: [HNOI2015]开店 Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 2168 Solved: 947[Submit][Status] ...
- 【BZOJ4012】[HNOI2015]开店 动态树分治+二分
[BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...
- 洛谷 P3241 [HNOI2015]开店 解题报告
P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...
- [HNOI2015]开店 树链剖分,主席树
[HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- BZOJ4012: [HNOI2015]开店【动态点分治】
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
- BZOJ4012 [HNOI2015]开店 (动态点分治)
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
- P3241 [HNOI2015]开店 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
随机推荐
- 07 YAPI/基础设施 - DevOps之路
07 YAPI/基础设施 - DevOps之路 文章Github地址,欢迎start:https://github.com/li-keli/DevOps-WiKi 简介 YApi 是一个可本地部署的. ...
- 蛙蛙推荐: TensorFlow Hello World 之平面拟合
tensorflow 已经发布了 2.0 alpha 版本,所以是时候学一波 tf 了.官方教程有个平面拟合的类似Hello World的例子,但没什么解释,新手理解起来比较困难. 所以本文对这个案例 ...
- 小谈UAT(验收测试)
验收测试人员的测试任务: 1.验收人员是提出需求的人员,所以对需求最为熟悉,最主要测试功能的遗漏或者多余2.系统测试人员重点在测试功能的正确性和非功能的符合性,当然也希望验收人员测试功能的正确性3.因 ...
- PS制作动感酷炫水人街舞照
一.打开原图素材,用钢笔工具把人物从图中扣取出来,新建一个812 * 1024像素的文档,把抠出的人物拖进来,过程如下图. 二.用你习惯的修图工具把人物的手.脸部.腰部.袜子通通修掉.再补回衣服在透视 ...
- openstack-KVM安装与使用
一.KVM安装 1.安装条件 VT-x BIOS Intel9R) Virtualization Tech [Enabled] cat /proc/cpuinfo | grep -e vmx -e n ...
- rbac组件权限按钮,菜单,可拔插
1.通用模板 overflow: auto; //在a和b模板中进行切换 a 模板 :左侧菜单跟随滚动条 b模板 左侧以及上不动 **** <!DOCTYPE html> <h ...
- 福州大学软件工程1816 | W班 第4次作业(团队展示)成绩排名
作业链接 评分细则 队员姓名与学号(标记组长),其中4-7人一组,特殊情况经老师允许后可以突破限制:(1分) 队名(体现项目内容,并要求有亮点与个性):(1分) 拟作的团队项目描述:一句话(中英文不限 ...
- 局域网 服务器 https
局域网内搭建一个服务器,可以使用 https 吗 - V2EXhttps://www.v2ex.com/t/472394 局域网内多台机器使用自签发证书架设https网站二:实施 - 左直拳的马桶_日 ...
- 原生node路由操作以及注意事项
var http = require("http"); var url = require("url"); var ejs = require("ej ...
- Linux 查找文件命令 find whereis locate
Linux 有三个查找文件的命令:find, whereis, locate 其中find 不常用,whereis与locate经常使用,因为find命令速度较慢,因为whereis与locate是利 ...