主席树 + 树上倍增 ---- codeforces 587C[树上倍增或者主席树]
题目链接
给定一棵n个点的树,给定m个人(m≤n)在哪个点上的信息,每个点可以有任意个人;然后给q个询问,每次问u到v上的路径有的点上编号最小的k(k≤10)个人(没有那么多人就该有多少人输出多少人)。给定一棵n个点的树,给定m个人(m≤n)在哪个点上的信息,每个点可以有任意个人;然后给q个询问,每次问u到v上的路径有的点上编号最小的k(k≤10)个人(没有那么多人就该有多少人输出多少人)。给定一棵n个点的树,给定m个人(m≤n)在哪个点上的信息,每个点可以有任意个人;然后给q个询问,每次问u到v上的路径有的点上编号最小的k(k≤10)个人(没有那么多人就该有多少人输出多少人)。
解法一:树上倍增法:
解题思路:观察那个数据,因为k的大小只有10,那么我们对于每个点就可以暴力求出前k小的数,用倍增的思想:在[l,r]区间内部前k小数就是[l,l+2i−1]和[l+2i,r]区间内的第k小值在[l,r]区间内部前k小数就是[l,l+2^i-1]和[l+2^i,r]区间内的第k小值在[l,r]区间内部前k小数就是[l,l+2i−1]和[l+2i,r]区间内的第k小值
这里合并有个小技巧:因为每个小区间都是单调的所以我们求第k小的时候我们可以用归并的思想去合并区间的信息
代码
#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 4e5 + 10, mod = 1e9 + 7;
const int maxn = 4e5 + 10;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
const int BUF=30000000;
char Buf[BUF],*buf=Buf;
template<typename T> void read(T &a)
{for(a=0;*buf<48;buf++);while(*buf>47) a=a*10+ *buf++ -48;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
int n, m ,q;
vector<int> G[N];
vector<int> pre[N][30];
int fa[N][20], depth[N];inline vector<int> Merge(vector<int> a, vector<int> b) {//合并前10小的数vector<int> ans;int poia = 0, poib = 0; while(ans.size() < 10 && poia < a.size() && poib < b.size()) {if(a[poia] < b[poib]) ans.push_back(a[poia ++]);else ans.push_back(b[poib ++]);}while(ans.size() < 10 && poia < a.size()) ans.push_back(a[poia ++]);while(ans.size() < 10 && poib < b.size()) ans.push_back(b[poib ++]);return ans;
}inline void dfs(int u, int f) {fa[u][0] = f;for(int i = 1; i <= 17; ++ i)fa[u][i] = fa[fa[u][i - 1]][i - 1];for(int j = 1; j <= 17; ++ j) {pre[u][j] = Merge(pre[u][j - 1],pre[fa[u][j - 1]][j - 1]);}depth[u] = depth[f] + 1;for(auto it : G[u]) {if(it == f)continue;dfs(it,u);}
}inline int LCA(int u, int v) {if(depth[u] > depth[v]) swap(v,u);int delta = depth[v] - depth[u];for(int i = 0; i <= 17; ++ i)if(delta >> i & 1) v = fa[v][i];if(u == v) return v;for(int i = 17; i >= 0; -- i)if(fa[u][i] != fa[v][i])u = fa[u][i], v = fa[v][i];return fa[u][0];
}inline vector<int> slove(int u, int v) {vector<int> res;int delta = depth[u] - depth[v];for(int j = 0; j <= 17 && u; ++ j) if(delta >> j & 1) res = Merge(res,pre[u][j]), u = fa[u][j];return res;
}int main()
{fread(Buf,1,BUF,stdin);read(n,m,q);for(int i = 0; i < n - 1; ++ i) {int l, r;read(l,r);G[l].push_back(r);G[r].push_back(l);}for(int i = 1; i <= m; ++ i) {int x;read(x);pre[x][0].push_back(i);}for(int i = 1; i <= n; ++ i) sort(pre[i][0].begin(),pre[i][0].end());dfs(1,0);while(q --) {int u, v, a;read(u,v,a);int lca = LCA(u,v);vector<int> ans, res;ans = slove(u,lca);res = slove(v,lca);res = Merge(ans,res);res = Merge(res,pre[lca][0]); //因为LCA还没被计算过//..........................................................if(!res.size()) printf("0\n");else cout << min((int)res.size(),a) << " ";for(int i = 0; i < min(a,(int)res.size()); ++ i) {printf("%d",res[i]);if(i < min(a,(int)res.size()) - 1) printf(" ");else printf("\n"); }}return 0;
}
解法2:主席树,因为树上信息具有可加性所以我们可以按照dfs序对这颗树建立一个主席树就是每个点到根节点的路径区间建立主席树,多次插入,那么要求u和v之间的路径信息的话那么就要[root,u]+[root,v]−[root,lca]−[root,fa[lca]][root,u]+[root,v]-[root,lca]-[root,fa[lca]][root,u]+[root,v]−[root,lca]−[root,fa[lca]],这个可以有倍增去维护
代码:
#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
const int maxn = 4e5 + 10;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
int n, m, q, maxv;
//.......................建图
struct Node {/* data */int to, nxt;
}edge[N];
int head[N], cnt;
vector<int> node[N];inline void add(int from, int to) {edge[cnt] = (Node){to,head[from]};head[from] = cnt ++;
}
//.....................主席树
struct Tree {int lson, rson, cnt;
}tr[N * 40];
int root[N];
int idx = 0;inline int build(int l, int r) {int now = ++ idx;if(l == r) return now;tr[now].lson = build(l,mid), tr[now].rson = build(mid+1,r);return now;
}inline int insert(int pre, int l, int r, int k) {int poi = ++ idx;tr[poi] = tr[pre];if(l == r) {tr[poi].cnt ++;return poi;} if(k <= mid) tr[poi].lson = insert(tr[pre].lson,l,mid,k);else tr[poi].rson = insert(tr[pre].rson,mid+1,r,k);tr[poi].cnt = tr[tr[poi].lson].cnt + tr[tr[poi].rson].cnt;return poi;
}inline int query(int lpoi, int rpoi, int lcapoi, int falcapoi, int l, int r, int k) {if(l == r) return l;int Eps = tr[tr[lpoi].lson].cnt + tr[tr[rpoi].lson].cnt - tr[tr[lcapoi].lson].cnt - tr[tr[falcapoi].lson].cnt;if(k <= Eps) return query(tr[lpoi].lson,tr[rpoi].lson,tr[lcapoi].lson,tr[falcapoi].lson,l,mid,k);else return query(tr[lpoi].rson,tr[rpoi].rson,tr[lcapoi].rson,tr[falcapoi].rson,mid+1,r,k-Eps);
}//...................倍增求LCAint fa[N][20], depth[N];
inline void dfs(int u, int f) {if(node[u].size()) {root[u] = insert(root[f],1,maxv+1,node[u][0]);for(int i = 1; i < node[u].size(); ++ i)root[u] = insert(root[u],1,maxv+1,node[u][i]);}else root[u] = root[f];fa[u][0] = f; depth[u] = depth[f] + 1;for(int i = 1; i <= 17; ++ i)fa[u][i] = fa[fa[u][i - 1]][i - 1];for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(v == f) continue;dfs(v,u);}
}
//.....................................
inline int LCA(int u, int v) {if(depth[u] > depth[v]) swap(v,u);int delta = depth[v] - depth[u];for(int i = 0; i <= 17; ++ i)if(delta >> i & 1) v = fa[v][i];if(u == v) return v;for(int i = 17; i >= 0; -- i)if(fa[u][i] != fa[v][i])u = fa[u][i], v = fa[v][i];return fa[u][0];
}
//.......................................
inline void debug(int rt, int l, int r) {cout << tr[tr[rt].lson].cnt << " ";cout << tr[tr[rt].rson].cnt << "\n";cout << l << " " << r << endl;cout << "-------------" << endl;if(l == r) {if(tr[rt].cnt) cout << l << " debug" << endl;return;}debug(tr[rt].lson,l,mid);debug(tr[rt].rson,mid+1,r);
}
//.......................................
int ans[N], poi;
//.......................................
int main() {ms(head,-1);read(n,m,q);maxv = max(n,m);for(int i = 0; i < n - 1; ++ i) {int l, r;read(l,r);add(l,r), add(r,l);} for(int i = 1; i <= m; ++ i){int x;read(x);node[x].push_back(i);}root[0] = build(1,maxv+1);dfs(1,0);while(q --) {int u,v,a;read(u,v,a);int lca = LCA(u,v);for(int i = 1; i <= min(a,m); ++ i) {int tmp = query(root[u],root[v],root[lca],root[fa[lca][0]],1,maxv+1,i);if(tmp > maxv) continue;ans[poi ++] = tmp;}printf("%d ",poi);if(poi == 0) puts("");for(int i = 0; i < poi; ++ i) printf("%d%c",ans[i]," \n"[i == poi - 1]);poi = 0;}return 0;
}
主席树 + 树上倍增 ---- codeforces 587C[树上倍增或者主席树]相关推荐
- 刷题总结——树的同构(bzoj4337 树上hash)
Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T ...
- 树链剖分(维护树上信息)
学习前请先掌握线段树:线段树(维护区间信息) 一,思想: 将一颗树拆成多条线性链以方便维护(如线段树). 先给出以下定义(通过这些定义我们就可以组成链): 重儿子:子节点最多的儿子就是重儿子 轻儿子: ...
- CodeForces - 1364D Ehabs Last Corollary(dfs树找最小环)
题目链接:点击查看 题目大意:给出一个由 n 个结点和 m 条边构成的无向图,再给出一个 k ,需要在图中完成下面任意一种操作: 找到一个大小恰好为 的独立集 找到一个大小不超过 k 的环 题目分析 ...
- Super Mario HDU - 4417(主席树解决区间数字小于k的个数||线段树+离线)
Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...
- Codeforces 444C DZY Loves Colors 线段树区间更新
// Codeforces 444C DZY Loves Colors 线段树区间更新// 题目链接:// http://codeforces.com/problemset/problem/444/C ...
- CodeForces - 1405E Fixed Point Removal(线段树+思维)
题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a ,规定当 a[ i ] == i 时,位置 i 可以被删除掉,后面位置会合并上来,现在需要回答 m 次询问,每次询问会问禁用掉后面 x 个 ...
- Zju2112 Dynamic Rankings(树状数组套可持久化权值线段树)
Zju2112 Dynamic Rankings description solution code description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须 ...
- 小A与欧拉路 (树加边求最小权值欧拉路+树的直径)
链接:https://ac.nowcoder.com/acm/contest/369/C 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...
- poj 2352 Stars 线段树(先建后查/边建边查)/树状数组三种方法思路详解,带你深入了解线段树难度⭐⭐⭐★
poj 2352 Stars 目录 poj 2352 Stars 1.树状数组 2.线段树,先建树后查找 3.线段树,边建树边查找 Description Astronomers often exam ...
最新文章
- BZOJ 3420: Poi2013 Triumphal arch
- android 定位 闪退_Android使用百度地图出现闪退及定位时显示蓝屏问题
- dz mysql日志清理_Discuz教程:如何准确的清理数据库
- RabbitMQ原理RabbitMQ各组件作用RabbitMQ使用场景
- Openssl 之大数运算函数 BN
- python 流式编程_python 使用yield进行数据的流式处理
- VS2010皮肤控件介绍
- ARM产品系列对应架构图
- STM32L051测试 (四、Flash和EEPROM的读写)
- 联想笔记本桌面计算机不见了,联想电脑任务栏不见了怎么还原
- Adobe Dreamweaver CS6 安装教程详解「附pj文件」
- 创新专题一:省份层面(创新效率、创新能力、投入产出、高质量发展等)
- iphone 的文件目录和简单介绍
- win8/win8.1提示在关闭了用户控制的情况下 无法打开这个应用
- 对战平台虚拟War3局域网的原理
- 计算机硬件故障可分为哪几类,计算机硬件故障有哪些(浅谈计算机硬件故障的识别与处理)...
- 智慧社区管理平台该如何选择?
- 如何做一个基于微信高校食堂就餐预约小程序序系统毕业设计毕设作品
- thingsboard遥测数据确认机制
- Git push之后回滚
热门文章
- 汇编语言(王爽 第三版) ret retf总结 以及检测点10.1
- 无需用户输入,Adobe提出自动生成高质量合成图像新方法
- 理解卷积神经网络的局限
- 百度不到的硬核资源,8h删,抓紧收藏!
- Commonjs规范
- SSH:Oracle数据库基础
- 【BZOJ】1711: [Usaco2007 Open]Dining吃饭
- Swift 3.0封装 URLSession 的GET/SET方法代替 Alamofire
- 随办 企业打造完美执行团队的终极利器
- vbscript input select 添加个option根据value值到指定位置--相当于排序