SPOJ1487. Query on a tree III 树链剖分+主席树

来源:互联网 发布:网络课程的内容有哪些 编辑:程序博客网 时间:2024/06/06 19:06

思路还是不太难的,只是我没想到。。。就是把点映射到数列上(就是剖分),然后求区间第K大(同一棵子树在数列上的位置总是连续的,所以把树链剖分看成一种特殊的hash)。

限制十分坑爹,在spoj上时间限制很紧,原先写主席树TLE了。后来去bzoj上提交,然后MLE了尴尬(spoj空间256M,bzoj只有64M),只能不断地删掉没用的数组,然后重复用,所以代码写得很乱。不过在bzoj上AC之后,在spoj上竟然也AC了(我没有优化时间啊),果真坑爹。

感觉主席树的常数和空间都有点大,不知道需不需要学学划分树。

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#include <algorithm>#define MIN(a,b) ((a<b)?a:b)#define MAX(a,b) ((a>b)?a:b)#define MEM(a) memset(a,0,sizeof(a))#define mid ((l+r)>>1)using namespace std;const int MAXN = 100010;const int MAXM = 2011110;const int INF = 999999999;int f[MAXN], son[MAXN], s[MAXN], h[MAXN], w[MAXN], v[MAXN];int Time;int root[MAXN], tr[MAXM], ch[MAXM][2];struct edge{int u, next;}e[MAXN << 1];int head[MAXN], nume, numn;inline void addedge(int x, int u){e[++nume].u = u;e[nume].next = head[x];head[x] = nume;}void dfs1(int c){s[c] = 1;for (int i = head[c]; i; i = e[i].next){if (e[i].u != f[c]){f[e[i].u] = c;dfs1(e[i].u);s[c] += s[e[i].u];if (s[e[i].u] > s[son[c]]) son[c] = e[i].u;}}}void dfs2(int c, int tp){h[c] = ++Time; w[Time] = c;if (!son[c]) return;dfs2(son[c], tp);for (int i = head[c]; i; i = e[i].next) if (e[i].u != f[c] && e[i].u != son[c]) dfs2(e[i].u, e[i].u);}void build(int &cx, int &cy, int l, int r, int x){if (!cx) cx = ++numn;if (l == r){tr[cx] = tr[cy] + 1;return;}int m = mid;tr[cx] = tr[cy] + 1;if (x <= m){build(ch[cx][0], ch[cy][0], l, m, x);ch[cx][1] = ch[cy][1];}else{build(ch[cx][1], ch[cy][1], m + 1, r, x);ch[cx][0] = ch[cy][0];}}int query(int cx, int cy, int l, int r, int x){int t = tr[ch[cx][0]] - tr[ch[cy][0]], m = mid;if (l == r) return f[l];if (t >= x) return query(ch[cx][0], ch[cy][0], l, m, x);else return query(ch[cx][1], ch[cy][1], m + 1, r, x - t);}inline bool cmp(edge a, edge b) { return a.u < b.u; }void work(){int i, j, n, t1, t2, t3, tx, ty, t, q, ans;char c[100];Time = nume = numn = 0;scanf("%d", &n);for (i = 1; i <= n; ++i){scanf("%d", &v[i]);e[i].u = v[i]; //离散化,借用边的数组(原先以为会MLE,所以代码写得很乱)e[i].next = i;}sort(e + 1, e + n + 1, cmp); for (i = 1; i <= n; ++i) v[e[i].next] = i;for (i = 1; i < n; ++i){scanf("%d%d", &t1, &t2);addedge(t1, t2);addedge(t2, t1);}scanf("%d", &q);dfs1(1);dfs2(1, 1);for (i = 1; i <= n; ++i) f[v[i]] = i;//f数组用作v的反向索引,输出答案用到for (i = 1; i <= n; ++i) build(root[i], root[i - 1], 1, n, v[w[i]]);//构树for (i = 1; i <= q; ++i){scanf("%d%d", &t1, &t2);printf("%d\n", query(root[h[t1] + s[t1] - 1], root[h[t1] - 1], 1, n, t2));}}int main(){work();return 0;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 新生儿吃奶老是呛到怎么办 刚生小狗不吃奶怎么办 刚出生的小羊不吃奶怎么办 羔羊走路不稳不吃奶怎么办 新生儿喝奶老是呛到怎么办 宝宝吃母乳呛到怎么办 宝宝一直睡觉不吃奶怎么办 3个月婴儿不吃奶怎么办 新生婴儿晚上不睡觉怎么办 宝宝肚子胀不吃奶怎么办 宝宝25天不睡觉怎么办 50天婴儿不吃奶怎么办 儿子关在房间玩电脑怎么办? 宽带拨号上网账号密码忘了怎么办 双眼皮割的太宽怎么办 营业执照异常名录移除注销怎么办 工商局注册后骚扰电话怎么办 单位工作失误医保断交7年怎么办 大门对大门怎么办?巧用天官赐福 委托书公司名称打错了怎么办 招行ubank不对账怎么办 信贷公司利息高不合理怎么办 衣服上的logo掉怎么办 ui设计师接不到私活怎么办 微信打开很慢怎么办 小泰迪感冒加身上结痂怎么办 法斗眼睛肿了怎么办 地图鱼身上有白点怎么办 人被广告牌砸了怎么办 小米手机出现繁体中文英文怎么办 雅思考试把姓名写错了怎么办 房贷的流水账假怎么办 报到证报道期限过期了怎么办 注销公司公章丢了怎么办 家里的猫太调皮怎么办 孩子纹身了我该怎么办 46天婴儿感冒了怎么办 狗病了不吃东西怎么办 幼儿急诊见风了怎么办 哺乳期乳房有硬块而且疼怎么办 哺乳期乳头破裂乳房似针扎怎么办