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}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...
随机推荐
- Item 13: 比起iterator优先使用const_iterator
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 STL中的const_iterator等价于pointers-to ...
- 剑指offer--4.重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2, ...
- python-re模块-54
import re # findall # search # match ret = re.findall('[a-z]+', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列 ...
- codeforces#580 D. Kefa and Dishes(状压dp)
题意:有n个菜,每个菜有个兴奋值,并且如果吃饭第i个菜立即吃第j个菜,那么兴奋值加ma[i][j],求吃m个菜的最大兴奋值,(n<=18) 分析:定义dp[status][last],statu ...
- JavaScript中防止重复提交
有这么一种情况: 页面有一个按钮,点击之后会触发Ajax请求,但是用户在点击之后,不知道是否点成功了,于是又点了一下,如果不加处理的话,就会进行两次Ajax请求,并且请求的数据都是一样的,对后端的程序 ...
- C#设计模式之4:装饰者模式
装饰者模式 背景是有一家星巴兹咖啡店,由于客源充足,所以决定重新设计他们的收费系统,以前的收费系统中只定义了一个表示饮料的Beverage的基类,它里面定义了一个Cost的方法用来计算饮料的花费,但是 ...
- java线程池实现原理
(1):线程池存在哪些状态,这些状态之间是如何进行切换的呢? (2):线程池的种类有哪些? (3):创建线程池需要哪些参数,这些参数的具体含义是什么? (4):将任务添加到线程池之后运行流程? (5) ...
- Latex常用软件
Linux texMaker sudo apt-get install texlive-full sudo apt-get install texmaker
- 阿里巴巴 Java开发手册1.4.0
<阿里巴巴Java开发手册1.4.0>下载地址: 下载地址:https://102.alibaba.com/downloadFile.do?file=1528269849853/Java_ ...
- 字符串正则替换replace第二个参数是函数
zepto中 //将字符串转成驼峰式的格式 camelize = function (str) { return str.replace(/-+(.)?/g, function (match, chr ...