spoj 10628 Count on a tree
2015-10-26 20:07
267 查看
// spoj 10628 Count on a tree // // 题目大意: // 一棵树上,节点有权值.给q个查询,询问u到v路径上第k小的值 // // 解题思路: // // 函数式线段树.首先离散化,将最后不同的元素的个数设为tot记录下来,然后 // 先建立一颗1-tot的空的线段树.按照dfs序列建立函数式线段树.问什么按照dfs序列. // 因为这样可以将树上节点变成线性结构.我们需要的答案只与四颗树有关即rt[u], // rt[v],rt[LCA(u,v)],rt[father[LCA(u,v)]].函数式线段树也满足加减性质.所以十分 // 方便. // // 感悟: // // 这道题搞了好久,是看着大神的代码做的.主要是学习一下函数式线段树.然而我敲出来 // 就是wa.开始瞎bb弄了个LCA-倍增算法的模板一套,一直wa.我还没怀疑LCA错了.最后只差LCA // 了,我才发现LCA真的错了...然后怒用树链剖分的方式求LCA,结果过了~~~心情还是很激动的呢 // 感觉函数式线段树就是每次对于前面一颗线段树建立一个新的节点保存之前没有修改的节点 // 的信息,而且更省空间.主要作用应该是计数问题,继续加油吧~~~FIGHTING!!! #include <cstring> #include <algorithm> #include <iostream> #include <cstdio> #include <cmath> #include <string> #include <vector> #include <queue> #define For(x,a,b,c) for (int x = a; x <= b; x += c) #define Ffor(x,a,b,c) for (int x = a; x >= b; x -= c) #define cls(x,a) memset(x,a,sizeof(x)) using namespace std; typedef long long ll; const double PI = acos(-1.0); const double eps = 1e-9; const int MAX_N = 1e5 + 10000; const int INF = 1e9 + 7; const ll MOD = 1e9 + 7; int N,M; int a[MAX_N]; int b[MAX_N]; vector<int> g[MAX_N]; //int pa[MAX_N][20]; //int dep[MAX_N]; int top[MAX_N]; int idx[MAX_N]; int siz[MAX_N]; int son[MAX_N]; int dep[MAX_N]; int father[MAX_N]; struct node{ int ls; int rs; int cnt; }; int tot; struct IntervalTree{ node p[MAX_N * 20]; int rt[MAX_N]; int Siz; void init(){ Siz = 1; } int build(int L,int R){ int rt = Siz++; p[rt].cnt = 0; if (L == R){ return rt; } int M = (L + R) >> 1; p[rt].ls = build(L,M); p[rt].rs = build(M+1,R); return rt; } int update(int rt,int L,int R,int q,int v){ int nrt = Siz++; p[nrt] = p[rt]; p[nrt].cnt += v; if (L == R){ return nrt; } int M = (L + R) >> 1; if (q <= M) p[nrt].ls = update(p[rt].ls,L,M,q,v); else p[nrt].rs = update(p[rt].rs,M+1,R,q,v); return nrt; } int query(int rtl,int rtr,int rlca,int rf_lca,int L,int R,int k){ if (L == R){ return L; } int M = (L + R) >> 1; int tmp = p[p[rtl].ls].cnt + p[p[rtr].ls].cnt - p[p[rlca].ls].cnt - p[p[rf_lca].ls].cnt; if (tmp >= k){ return query(p[rtl].ls,p[rtr].ls,p[rlca].ls,p[rf_lca].ls,L,M,k); }else return query(p[rtl].rs,p[rtr].rs,p[rlca].rs,p[rf_lca].rs,M+1,R,k - tmp); } }it; void dfs(int u,int fa,int d){ dep[u] = d; father[u] = fa; son[u] = 0; siz[u] = 1; //pa[u][0] = fa; For(i,0,g[u].size()-1,1){ int v = g[u][i]; if (v == fa) continue; dfs(v,u,d+1); siz[u] += siz[v]; if (siz[son[u]] < siz[v]) son[u] = v; } } void dfs_2(int u,int tp){ top[u] = tp; //idx[u] = id++; if (son[u]) dfs_2(son[u],tp); For(i,0,g[u].size()-1,1){ int v =g[u][i]; if (v == father[u] || v == son[u]) continue; dfs_2(v,v); } } int LCA_init(){ dfs(1,0,1); dfs_2(1,1); } int LCA(int u,int v){ int p = top[u]; int q = top[v]; while(p != q){ if (dep[p] < dep[q]){ swap(p,q); swap(u,v); } u = father[p]; p = top[u]; } if (dep[u] > dep[v]) swap(u,v); return u; } //void LCA_init(){ // cls(pa,-1); // dfs(1,1,1); // for (int j = 1;(1<<j) <= N; j++){ // for (int i = 1;i <= N ;i ++){ // pa[i][j] = pa[pa[i][j-1]][j-1]; // } // } //} // //int LCA(int u,int v){ // int i,j; // // if (dep[u] < dep[v]) // swap(u,v); // for (i = 0;(1<<i) <= dep[u];i++); // // i--; // // for (j = i; j>= 0;j --) // if (dep[u] - (1<<j) >= dep[v]) // u = pa[u][j]; // // if (u == v) // return u; // // for (j = i; j >=0;j --){ // if (pa[u][j]!=-1 && pa[u][j]!=pa[v][j]){ // u = pa[u][j]; // v = pa[v][j]; // } // } // return pa[u][0]; //} void dfs(int u,int fa){ For(i,0,g[u].size()-1,1){ int v =g[u][i]; if (v == fa) continue; it.rt[v] = it.update(it.rt[u],1,tot,a[v],1); //it.rt[v] = it.update(it.rt[u],a[v],1); dfs(v,u); } } void print(){ For(i,1,N,1) printf("%d ",a[i]); cout << endl; } void input(){ int m = 0; For(i,1,N,1){ scanf("%d",&a[i]); b[i] = a[i]; } For(i,1,N-1,1){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } sort(b+1,b+N+1); tot = unique(b+1,b+N+1) - b - 1; // b[tot + 1] = INF; //cout << " ---" << tot << endl; it.init(); it.rt[0] = it.build(1,tot); For(i,1,N,1){ a[i] = lower_bound(b,b+tot+1,a[i]) - b; } //print(); it.rt[1] = it.update(it.rt[0],1,tot,a[1],1); //it.rt[1] = it.update(it.rt[0],a[1],1); dfs(1,-1); LCA_init(); } void solve(){ For(i,1,M,1){ int u,v,k; scanf("%d%d%d",&u,&v,&k); int t = LCA(u,v); //printf("%d %d %d %d\n",it.rt[u],it.rt[v],t,k); printf("%d\n",b[it.query(it.rt[u],it.rt[v],it.rt[t],it.rt[father[t]],1,tot,k)]); //printf("%d\n",b[it.query(it.rt[u],it.rt[v],t,k)]); } } void init(){ For(i,1,N,1){ g[i].clear(); } cls(dep,0); } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); while(scanf("%d%d",&N,&M)!=EOF){ init(); input(); solve(); } return 0; }
相关文章推荐
- 从Eclipse转移到IntelliJ IDEA一点心得
- MySQL锁机制及优化
- iOS RTMP 视频直播开发笔记(6)- 封包 FLV
- 学习笔记cocos2d-x之元素介绍
- [74]Search a 2D Matrix
- UE4学习笔记-人物旋转控制(c++实现)
- PHP empty和isset区别
- 部署asp.net网站的小问题
- Linux-CentOS 安装PHP扩展库Imagick
- iOS RTMP 视频直播开发笔记(5)- iOS H.264 实时硬编码实现原理
- C语言:实现一个函数itoa(int n,char s[]),将整数n这个数字转换为对应的字符串,保存到s中
- Esper——Context
- 谈谈关于Python里面小数点精度控制的问题
- Deploy One Project on Heroku (Week IV)
- 家庭作业6.32
- java22
- (原创)c#学习笔记06--函数02--变量的作用域01--其他结构中变量的作用域
- 飞凌OK6410开发板SDIO无线8189WIFI模块驱动移植
- Android中悬浮窗口的实现原理和示例代码
- 智能车学习(七)——按键矩阵的实现