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}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
随机推荐
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- 网络拓扑自动发掘之三层设备惯用的SNMP OID的含义
原文地址:https://blog.csdn.net/maty_wang/article/details/81305070 1. ipNetToMediaIfIndex Name/OID: ipNet ...
- Less or Equal CodeForces - 977C (sort+细节)
You are given a sequence of integers of length nn and integer number kk. You should print any intege ...
- 关于iframe页面里的重定向问题
最近公司做的一个功能,使用了iframe,父页面内嵌子页面,里面的坑还挺多的,上次其实就遇到过,只不过今天在此描述一下. 请允许我画个草图: 外层大圈是父级页面,里层是子级页面,我们是在父级引用子级页 ...
- Redis缓存用起来
Redis缓存用起来 1. 引言 创建任务时我们需要指定分配给谁,Demo中我们使用一个下拉列表用来显示当前系统的所有用户,以供用户选择.我们每创建一个任务时都要去数据库取一次用户列表,然后绑定到用户 ...
- VO和DO转换(二) BeanUtils
VO和DO转换(一) 工具汇总 VO和DO转换(二) BeanUtils VO和DO转换(三) Dozer VO和DO转换(四) MapStruct BeanUtils是Spring提供的,通常项目都 ...
- 简述HTTP协议
引言 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网服务器传输超文本到本地浏览器的传送协议.HTTP 是基于 TCP/IP 协议通信协议 ...
- mongoDB 安装和配置环境变量,超详细版本
下载mongoDB进行安装:https://www.mongodb.com/ 到Community Se ...
- JavaScript生成二维码图片
1.引入一个二维码工具的js文件,同时需要引入jquery文件 下面是jquery.qrcode.min.js文件内容: (function(r){r.fn.qrcode=function(h){va ...
- awk骚操作
一.awk自加 [root@168web3 ~]# head /data/logs/cloud_monitor_rds_cpu.log |awk '{sum+=$NF}END{print sum}' ...