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}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
随机推荐
- 使用Thrift让Python和C#可以相互调用
在聊如何使用Thrift让Python和C#可以互相调用之前,我们先来看看下面的话题. 一.什么是微服务.微服务的特征.诞生的背景.优势和不足 微服务:使用一套小服务来开发单个应用的方式,每个服务运行 ...
- 【React】开发一个城市选择控件
想到做这个,是因为无意中在github上看到了这一个仓库https://github.com/lunlunshiwo/ChooseCity,做的就是一个城市选择控件,是用vue写的,说的是阿里的一道题 ...
- 第四次oo博客
论述测试与正确性论证的效果差异 单元测试利用测试者构造的测试用例来检查类或方法的正确性,一般来说所需要测试的用例是无穷多的,通过人为构造代表性的测试用例来尽量测试所有代码.测试的优点在于不易出错,只要 ...
- 网络编程-TCP/IP
TCP/IP五层模型讲解(2分) 我们将应用层,表示层,会话层并作应用层,从tcp/ip五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议 就理解了整个互联网通信的原理. 首先,用户感知到的 ...
- 牛客练习赛35 C.函数的魔法
链接 [https://ac.nowcoder.com/acm/contest/32] 题意 题目描述 一位客人来到了此花亭,给了女服务员柚一个数学问题:我们有两个函数,F(X)函数可以让X变成(XX ...
- jconsole & jvisualvm远程监视websphere服务器JVM的配置案
jconsole是JDK里自带的一个工具,可以监测Java程序运行时所有对象的申请.释放等动作,将内存管理的所有信息进行统计.分析.可视化.我们可以根据这些信息判断程序是否有内存泄漏问题. 使用jco ...
- 如何优化Docker储存
大家在使用Docker的过程中,有没有想过,Docker在本地存储镜像时把文件存储在哪里了呢?有没有对文件的总大小做一定的限制呢?能不能调整本地存储的位置及总限制大小呢?今天,我们就从这些问题入手,来 ...
- Python_内置函数之zip
zip函数用于将可迭代的对象作为参数,将对象中的元素打包成一个个元祖,然后返回这些元祖组成的列表.如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同. l1 = [1, 2, 3] l2 ...
- Java 常见编码格式——URL、Base64
数据编码 我们对数据进行编码是因为在某些情况下,不能直接传输中文字符或者其他字符,比如在设置http协议的头部信息或者cookie时,如果value有中文字符,那么就需要将中文字符使用某种编码方式进行 ...
- 学习 yii2.0——视图之间相互包含
布局 首先创建一个布局文件simple.php,路径是在views/layout/目录下. <p>this is header</p> <?= $content ?> ...