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}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
随机推荐
- 关于VS2017 添加 EF的MVC控制器报错的解决方法
1. 错误描述 :no database provider has been configured fot this DbContext. 此类错误是上下文的注册造成的.解决方式在DBContext中 ...
- IIS 日志导入到数据库的方法
使用微软Log Parser 执行 logparser "SELECT * FROM d:\iislogs\u_ex18071705.log TO myTableName" -o: ...
- long long 的输入输出问题
参考博客:https://www.byvoid.com/zhs/blog/c-int64
- Yii1.1框架实现PHP极光推送消息通知
一.下载极光推送PHP SDK,解压后放在/protected/components/目录下,如下图所示: 二.完善修改下官方的demo例子,我这里复制一份demo,改为NotifyPush.php, ...
- (FZU 2150) Fire Game (bfs)
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2150 Problem Description Fat brother and Maze are playing ...
- p9半幺群
如何不理解划红线的地方?第二个划红线地方,请举一个例子 1.0不是幺元 2.f(1)=2, f(2)=1, f(3)=3, g(1)=2, g(2)=3, g(3)=1 fg不等于gf
- Hadoop01的主要总结
Hadoop (离线) 分布式的计算框架 scala---spark(实时计算框架)
- 第五章 动态SQL 批量操作
用于实现动态SQL的元素主要有 if trim where set choose(when.otherwise) foreach MyBatis 缓存 一级缓存 在test类中 调用相同的方法 第二 ...
- YOLO.h5 下载
链接:https://pan.baidu.com/s/1sTxkuaFWXqT4yXLHQ9BgUA 密码:ga0o fhwayd_w1231234asd><321$%
- AngularJS基于模块化的MVC实现
AngularJS基于模块化的MVC实现 <!DOCTYPE html> <html> <head> <meta charset="UTF-8&qu ...