几个月后的UPD:

学习完下面之后,实战中的总结:

0.比赛中正解就是kdtree的题目很少很少

1.几类优先考虑kdtree的题目:

  k(维度) >= 3 的题目

  二维平面上涉及区间标记的题目

2. 二维平面上的题目, n >= 5W 谨慎使用kdtree

     非强制在线考虑cdq套数据结构(不涉及标记的话基本考虑树状数组)

     强制在线考虑树状数组套主席树(该方法需要提前确定空间够不够O(nlogn2))

  几种方法的常数比较:cdq套树 < 树套树 < kdtree

  编程复杂度也是cdq最小,后面两个差不多

3.非写kdtree不可的题目,常数上的几个优化

 <0>快速读入,快速输出的话,不超过50W的个数基本没必要

 <1>重构kdtree的参数选择,插入多查询少的情况,最优参数是接近 0.5 + x / (x + y) 的

     x是插入个数,y是查询个数

          插入少查询多的话,最优参数其实是更接近 0.7 + x / (x + y) 的, 查询再多也不建议参数低于0.7

     当然最优参数的话,有时间可以自己去测试调整

 <2>其实update函数那里吧两个 if 直接写成 max / min 未必时间会差一点,可以自己尝试测试时间

学习资料在这里

对于k维KDTree,实际时间复杂度为O(N*N^(1-1/k))

build实现类似spaly,不断选一维从中间划分,可以循环选取维度,也可以rand % k

求最近点的query,重点在于其中的估价函数

求区间和的query,则和线段树类似

例题:

1) bzoj 2648求最近点

 /*为了维持树的平衡,可以一开始把所有点都读进来build
然后打flag标记该点是否被激活*/
#include <bits/stdc++.h> using namespace std; const int N = 5e5 + ; const int inf = << ; int n, m; int ql, qr, ans, tot, nowD;
//nowD = rand() & 1 ?
struct Node {
int d[]; bool operator < (const Node &a) const {
if (d[nowD] == a.d[nowD]) return d[!nowD] < a.d[!nowD];
return d[nowD] < a.d[nowD];
}
}pot[N]; struct node {
int min[], max[], d[];
node *c[]; node() {
min[] = min[] = max[] = max[] = d[] = d[] = ;
c[] = c[] = NULL;
} node(int x, int y); void update(); }t[N], Null, *root; node::node(int x, int y) {
min[] = max[] = d[] = x;
min[] = max[] = d[] = y;
c[] = c[] = &Null;
} inline void node::update() {
if (c[] != &Null) {
if (c[] -> max[] > max[]) max[] = c[] -> max[];
if (c[] -> max[] > max[]) max[] = c[] -> max[];
if (c[] -> min[] < min[]) min[] = c[] -> min[];
if (c[] -> min[] < min[]) min[] = c[] -> min[];
}
if (c[] != &Null) {
if (c[] -> max[] > max[]) max[] = c[] -> max[];
if (c[] -> max[] > max[]) max[] = c[] -> max[];
if (c[] -> min[] < min[]) min[] = c[] -> min[];
if (c[] -> min[] < min[]) min[] = c[] -> min[];
}
} inline void build(node *&o, int l, int r, int D) {
int mid = l + r >> ;
nowD = D;
nth_element(pot + l, pot + mid, pot + r + );
o = new node(pot[mid].d[], pot[mid].d[]); if (l != mid) build(o -> c[], l, mid - , !D);
if (r != mid) build(o -> c[], mid + , r, !D);
o -> update();
} inline void insert(node *o) {
node *p = root;
int D = ;
while () {
if (o -> max[] > p -> max[]) p -> max[] = o -> max[];
if (o -> max[] > p -> max[]) p -> max[] = o -> max[];
if (o -> min[] < p -> min[]) p -> min[] = o -> min[];
if (o -> min[] < p -> min[]) p -> min[] = o -> min[]; if (o -> d[D] >= p -> d[D]) {
if (p -> c[] == &Null) {
p -> c[] = o;
return;
} else p = p -> c[];
} else {
if (p -> c[] == &Null) {
p -> c[] = o;
return;
} else p = p -> c[];
}
D ^= ;
}
} inline int dist(node *o) {
int dis = ;
if (ql < o -> min[]) dis += o -> min[] - ql;
if (ql > o -> max[]) dis += ql - o -> max[];
if (qr < o -> min[]) dis += o -> min[] - qr;
if (qr > o -> max[]) dis += qr - o -> max[];
return dis;
} inline void query(node *o) {
int dl, dr, d0;
d0 = abs(o -> d[] - ql) + abs(o -> d[] - qr);
if (d0 < ans) ans = d0;
if (o -> c[] != &Null) dl = dist(o -> c[]);
else dl = inf;
if (o -> c[] != &Null) dr = dist(o -> c[]);
else dr = inf; if (dl < dr) {
if (dl < ans) query(o -> c[]);
if (dr < ans) query(o -> c[]);
} else {
if (dr < ans) query(o -> c[]);
if (dl < ans) query(o -> c[]);
}
} int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = ; i <= n; i ++)
cin >> pot[i].d[] >> pot[i].d[];
build(root, , n, ); for (int x, y, z; m --; ) {
cin >> x >> y >> z;
if (x == ) {
t[tot].max[] = t[tot].min[] = t[tot].d[] = y;
t[tot].max[] = t[tot].min[] = t[tot].d[] = z;
t[tot].c[] = t[tot].c[] = &Null;
insert(&t[tot ++]);
} else {
ans = inf, ql = y, qr = z;
query(root), printf("%d\n", ans);
}
}
return ;
}

3种写法可选

<1>插入的时候采用替罪羊树的方法来维护,子树太偏就直接重构

<2>一开始直接把所有点扔进kdtree,用flag来标记该点是否被激活

<3>直接插入不重构。事实上本题没有出极端数据导致树会特别偏,所以可过。这种写法需要稍稍注意常数

2) bzoj 4066 二维平面,单点修改,区间查询,强制在线

 #include <bits/stdc++.h>

 using namespace std;

 const int inf = 1e9;

 int n, m, tot, nowD;

 struct node {
int Max[], Min[], d[];
int sum, siz, val;
node *c[]; node() {
Max[] = Max[] = -inf;
Min[] = Min[] = inf;
sum = val = siz = ;
c[] = c[] = NULL;
d[] = d[] = ;
} void update();
}Null, nodes[], *temp[]; node *root = &Null; inline void node::update() {
siz = c[] -> siz + c[] -> siz + ;
sum = c[] -> sum + c[] -> sum + val;
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
}
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
}
} inline bool cmp(const node *a, const node *b) {
return a -> d[nowD] < b -> d[nowD];
} inline void traverse(node *o) {
if (o == &Null) return;
temp[++ tot] = o;
traverse(o -> c[]);
traverse(o -> c[]);
} inline node *build(int l, int r, int D) {
int mid = l + r >> ; nowD = D;
nth_element(temp + l, temp + mid, temp + r + , cmp);
node *res = temp[mid];
res -> Max[] = res -> Min[] = res -> d[];
res -> Max[] = res -> Min[] = res -> d[];
if (l != mid) res -> c[] = build(l, mid - , !D);
else res -> c[] = &Null;
if (r != mid) res -> c[] = build(mid + , r, !D);
else res -> c[] = &Null;
res -> update();
return res;
} int x, y, a, b, tmpD; node **tmp; inline void rebuild(node *&o, int D) {
tot = ;
traverse(o);
o = build(, tot, D);
} inline void insert(node *&o, node *p, int D) {
if (o == &Null) {o = p; return;}
if (p -> Max[] > o -> Max[]) o -> Max[] = p -> Max[];
if (p -> Max[] > o -> Max[]) o -> Max[] = p -> Max[];
if (p -> Min[] < o -> Min[]) o -> Min[] = p -> Min[];
if (p -> Min[] < o -> Min[]) o -> Min[] = p -> Min[];
o -> siz ++, o -> sum += p -> sum;
insert(o -> c[p -> d[D] >= o -> d[D]], p, !D);
if (max(o -> c[] -> siz, o -> c[] -> siz) > int(o -> siz * 0.75 + 0.5)) tmpD = D, tmp = &o;
} inline int query(node *o, int D) {
if (o == &Null) return ;
if (x > o -> Max[] || y > o -> Max[] || a < o -> Min[] || b < o -> Min[]) return ;
if (x <= o -> Min[] && y <= o -> Min[] && a >= o -> Max[] && b >= o -> Max[]) return o -> sum;
return (x <= o -> d[] && y <= o -> d[] && a >= o -> d[] && b >= o -> d[] ? o -> val : )
+ query(o -> c[], !D) + query(o -> c[], !D);
} int main() {
ios::sync_with_stdio(false);
cin >> m;
node *ttt = &Null;
for (int t, ans = ; ; ) {
cin >> t;
if (t == ) break;
if (t == ) {
cin >> x >> y >> a;
x ^= ans, y ^= ans, n ++;
nodes[n].sum = nodes[n].val = a ^ ans, nodes[n].siz = ;
nodes[n].Max[] = nodes[n].Min[] = nodes[n].d[] = x;
nodes[n].Max[] = nodes[n].Min[] = nodes[n].d[] = y;
nodes[n].c[] = nodes[n].c[] = &Null;
tmp = &(ttt), insert(root, &nodes[n], );
if (*tmp != &Null) rebuild(*tmp, tmpD);
} else {
cin >> x >> y >> a >> b;
x ^= ans, y ^= ans, a ^= ans, b ^= ans;
if (x > a) swap(x, a);
if (y > b) swap(y, b);
ans = query(root, );
printf("%d\n", ans);
}
}
return ;
}

正直写法,子树size过大就要Rebuild

判断rebuild的系数取的0.75,注意rebuild不是在回溯过程中当前子树不平衡就立刻重构

而是回溯过程中找到最靠近根的需要重构的子树根节点,然后对这棵树进行重构

详情看代码

不正直写法,新节点先存在数组里,查询时遍历该数组+查询kdtree

当数组size大于K时,把数组里的点放进kdtree并重构整颗kdtree

K取10000即可,可过

3) bzoj4154 二维平面,区间覆盖,单点查询

 #include <bits/stdc++.h>

 using namespace std;

 const int N = 1e5 + ;

 const int Mod = 1e9 + ;

 int nowD, x[], y[], z;

 struct node {
int Max[], Min[], d[];
int val, lazy;
node *c[]; node() {
c[] = c[] = NULL;
} void pushup(); void pushdown(); bool operator < (const node &a) const {
return d[nowD] < a.d[nowD];
}
}Null, nodes[N]; node *root = &Null; inline void node::pushup() {
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
}
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
}
} inline void node::pushdown() {
if (c[] != &Null) c[] -> val = c[] -> lazy = lazy;
if (c[] != &Null) c[] -> val = c[] -> lazy = lazy;
lazy = -;
} inline node *build(int l, int r, int D) {
int mid = l + r >> ; nowD = D;
nth_element(nodes + l, nodes + mid, nodes + r + );
node *res = &nodes[mid];
if (l != mid) res -> c[] = build(l, mid - , !D);
else res -> c[] = &Null;
if (r != mid) res -> c[] = build(mid + , r, !D);
else res -> c[] = &Null;
res -> pushup();
return res;
} inline int query(node *o) {
if (o == &Null) return -;
if (o -> lazy != -) o -> pushdown();
if (x[] > o -> Max[] || y[] > o -> Max[] || x[] < o -> Min[] || y[] < o -> Min[]) return -;
if (x[] == o -> d[]) return o -> val;
return max(query(o -> c[]), query(o -> c[]));
} inline void modify(node *o) {
if (o == &Null) return;
if (o -> lazy != -) o -> pushdown();
if (x[] > o -> Max[] || y[] > o -> Max[] || x[] < o -> Min[] || y[] < o -> Min[]) return;
if (x[] <= o -> Min[] && y[] <= o -> Min[] && x[] >= o -> Max[] && y[] >= o -> Max[]) {
o -> val = o -> lazy = z;
return;
}
if (x[] <= o -> d[] && y[] <= o -> d[] && x[] >= o -> d[] && y[] >= o -> d[]) o -> val = z;
modify(o -> c[]), modify(o -> c[]);
} int n, m, k, a[N], c[N], d[N]; int cnt, st[N], en[N], dfn[N], dep[N]; vector <int> e[N]; void dfs(int u) {
st[u] = ++ cnt, dfn[cnt] = u;
for (int v : e[u])
dep[v] = dep[u] + , dfs(v);
en[u] = cnt;
} int main() {
ios::sync_with_stdio(false);
int T, ans;
for (cin >> T; T --; ) {
cin >> n >> m >> k, ans = cnt = ;
for (int i = ; i <= n; i ++)
e[i].clear();
for (int u, i = ; i <= n; i ++) {
cin >> u;
e[u].push_back(i);
}
dfs();
for (int i = ; i <= n; i ++) {
nodes[i].Min[] = nodes[i].Max[] = nodes[i].d[] = i;
nodes[i].Min[] = nodes[i].Max[] = nodes[i].d[] = dep[dfn[i]];
nodes[i].val = , nodes[i].lazy = -;
}
root = build(, n, );
for (int u, v, w, i = ; i <= k; i ++) {
cin >> u >> v >> w;
if (w == ) {
x[] = st[u], y[] = dep[u];
ans = (ans + 1ll * i * query(root) % Mod) % Mod;
} else {
x[] = st[u], x[] = en[u];
y[] = dep[u], y[] = dep[u] + v;
z = w, modify(root);
}
}
cout << ans << endl;
}
return ;
}

重点在于观察到修改的是一定距离以内的子节点

所以考虑转换到二维平面,一维为dfs序,一维为dep

通过子树区间+深度区间限制,即可得到修改的点集

二维平面上区间覆盖+单点查询,kdtree即可

4) bzoj3489 求区间内最大的只出现过一次的数

 #include <bits/stdc++.h>

 using namespace std;

 const int N = 1e5 + ;

 const int Mod = 1e9 + ;

 int nowD, ans, x[], y[];

 int n, m, a[N], b[N], c[N], d[N];

 struct node {
int Max[], Min[], d[];
int val, maxv;
node *c[]; node() {
c[] = c[] = NULL;
val = maxv = ;
} void pushup(); bool operator < (const node &a) const {
return d[nowD] < a.d[nowD];
}
}Null, nodes[N]; node *root = &Null; inline void node::pushup() {
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> maxv > maxv) maxv = c[] -> maxv;
}
if (c[] != &Null) {
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Max[] > Max[]) Max[] = c[] -> Max[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> Min[] < Min[]) Min[] = c[] -> Min[];
if (c[] -> maxv > maxv) maxv = c[] -> maxv;
}
} inline node *build(int l, int r) {
int mid = l + r >> ; nowD = rand() % ;
nth_element(nodes + l, nodes + mid, nodes + r + );
node *res = &nodes[mid];
if (l != mid) res -> c[] = build(l, mid - );
else res -> c[] = &Null;
if (r != mid) res -> c[] = build(mid + , r);
else res -> c[] = &Null;
res -> pushup();
return res;
} inline int calc(node *o) {
if (y[] < o -> Min[] || x[] > o -> Max[] || x[] > o -> Max[] || y[] < o -> Min[]) return -;
return o -> maxv;
} inline void query(node *o) {
if (o -> val > ans && y[] >= o -> d[] && x[] <= o -> d[] && x[] <= o -> d[] && y[] >= o -> d[]) ans = o -> val;
int dl, dr;
if (o -> c[] != &Null) dl = calc(o -> c[]);
else dl = -;
if (o -> c[] != &Null) dr = calc(o -> c[]);
else dr = -;
if (dl > dr) {
if (dl > ans) query(o -> c[]);
if (dr > ans) query(o -> c[]);
} else {
if (dr > ans) query(o -> c[]);
if (dl > ans) query(o -> c[]);
} } int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = ; i <= n; i ++) {
cin >> a[i];
b[i] = d[a[i]];
d[a[i]] = i;
}
for (int i = ; i <= n; i ++) d[i] = n + ;
for (int i = n; i; i --) {
c[i] = d[a[i]];
d[a[i]] = i;
}
for (int i = ; i <= n; i ++) {
nodes[i].Min[] = nodes[i].d[] = b[i];
nodes[i].Max[] = nodes[i].d[] = c[i];
nodes[i].Max[] = nodes[i].Min[] = nodes[i].d[] = i;
nodes[i].val = nodes[i].maxv = a[i];
}
root = build(, n);
for (int l, r; m --; ) {
cin >> l >> r;
l = (l + ans) % n + ;
r = (r + ans) % n + ;
if (l > r) swap(l, r);
y[] = l - ;
x[] = r + ;
x[] = l, y[] = r;
ans = , query(root);
cout << ans << endl;
}
cout << endl;
return ;
}

考虑a[i]上一次出现,和下一次出现位置分别pre[i], suc[i]

即变成pre[i], i, suc[i]在[0, l - 1], [l, r], [r + 1, n + 1]之间的数的最大值

3维KDtree即可,注意也要使用ans与区间最值的关系来优化

注意到3维有不需要的变量,不需要维护,40s时限跑了39s+...

简单总结:

1) 解决求最值的问题,kdtree其实就是优化暴力,所以一般都需要估价函数优化才可以

2) 非最值问题,其实感觉更像线段树,但由于奇妙的原因,所以一次更新覆盖到的区间可能达到O(sqrt(n))个

3) 由于本质是暴力,所以常数比较重要,inline,子树非空才更新,估价函数,无用信息不更新...各种优化,一般而言10W已经是极限

4) 板子题不说, KDtree的题目需要从题中找到k维平面,然后区间修改和区间查询就完事了

5) 非强制在线题目,并不优先考虑kdtree,可以考虑树套树,kdtree不强制在线可以考虑排序降维

其他例题

5) bzoj4520 给N个点,求第K远点对

solution:可以看到k比较小,所以所有点建好kdtree,对每个点查询一下,维护出一个大小为k的堆

把n个点的堆进行合并,和并出大小为2k的堆,即得到答案

6) hdu 5992

可以考虑裸的3维kdtree,能过

考虑到n比较大,不强制在线,可以按价格排序,带插入的kdtree,需要重构

这个题我打训练赛写后一种排序重构写法T到自闭

然后把那个重构的参数调整成了0.95就过了...

后来仔细考虑了一下,这个题的特点在于N很大,M不大

20W个插入,只有2W个查询

如果正常的把参数设为0.75的话,实际效率是接近O(N^(3/2))的

但参数设的比较偏的话,会减少重构次数,查询的复杂度会增加

但实际总复杂度更接近O(M*N(1/2)),所以就能A了

所以通过这个题,我们推荐重构参数设为 M/(N + M) + 0.5

KD树学习小结的更多相关文章

  1. K-D树学习笔记

    这东西其实就是高维二叉树?(反正我只会二维的) 大概就是把一个高维矩形按每一维分,一个点(及其子树)就表示一个高维区间,乱搞一下,就……没了? //BZOJ4066 "简单"题 / ...

  2. 02-17 kd树

    目录 kd树 一.kd树学习目标 二.kd树引入 三.kd树详解 3.1 构造kd树 3.1.1 示例 3.2 kd树搜索 3.2.1 示例 四.kd树流程 4.1 输入 4.2 输出 4.3 流程 ...

  3. K-D树问题 HDU 4347

    K-D树可以看看这个博客写的真心不错!这里存个版 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 HDU 4349 #includ ...

  4. 统计学习方法学习(四)--KNN及kd树的java实现

    K近邻法 1基本概念 K近邻法,是一种基本分类和回归规则.根据已有的训练数据集(含有标签),对于新的实例,根据其最近的k个近邻的类别,通过多数表决的方式进行预测. 2模型相关 2.1 距离的度量方式 ...

  5. KD树小结

    很久之前我就想过怎么快速在二维平面上查找一个区域的信息,思考许久无果,只能想到几种优秀一点的暴力. Kd树就是干上面那件事的. 别的不多说,赶紧把自己的理解写下来,免得凉了. KD树的组成 以维护k维 ...

  6. 利用KD树进行异常检测

    软件安全课程的一次实验,整理之后发出来共享. 什么是KD树 要说KD树,我们得先说一下什么是KNN算法. KNN是k-NearestNeighbor的简称,原理很简单:当你有一堆已经标注好的数据时,你 ...

  7. react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

    react学习小结   本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...

  8. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  9. dubbo学习小结

    dubbo学习小结 参考: https://blog.csdn.net/paul_wei2008/article/details/19355681 https://blog.csdn.net/liwe ...

随机推荐

  1. ubuntu安装typora

    optional, but recommended sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AF ...

  2. 网页分享URL

    <a href="tencent://Message/?Uin=QQ号码&Site=qq联系">点击联系</a> 1.新浪微博:<a href ...

  3. 关于 node.js的request事件

    下面展示的是一个ajax一部提交的服务器端处理过程.node创建一个web服务器,并侦听8080端口.对于服务器,我们为其绑定了request事件,对于请求对象,我们为它绑定了data和end事件: ...

  4. JS连续滚动幻灯片:原理与实现

    什么是连续滚动幻灯片?打开一些网站的首页,你会发现有一块这样的区域:一张图片,隔一段时间滑动切换下一张:同时,图片两端各有一个小按钮,供你手动点选下一张:底部有一排小圆圈,供你选定特定的某帧图片.这就 ...

  5. VUE使用QRcode或者vue-qr生成二维码

    这里介绍两种vue生成二维码的方法 QRcode vue-qr vue-qr比QRcode功能多在可以在中间加logo 下面先介绍QRcode vue里安装qrcodejs的npm包 npm inst ...

  6. Entity Framework 4.3 中使用存储过程

    尽管 Entity Framework 4.3 都已经发布了,且表示在 EF 5 中性能将会有很大提升.但很多存储过程控,始终不会放弃使用存储过程,那今天就让我们看看在 EF 4.3 中怎么使用存储过 ...

  7. NOIP真题汇总

    想想在NOIP前总得做做真题吧,于是长达一个月的刷题开始了 涉及2008-2016年大部分题目 NOIP [2008] 4/4 1.传纸条:清真的三维DP 2.笨小猴:字符串模拟 3.火柴棒等式:打表 ...

  8. Linux文件系统inode、block解释权限(三)

    利用文件系统的inode和block来分析文件(目录)的权限问题. 为什么读取一个文件还要看该文件路径所有目录的权限? 为什么目录的w权限具有删除文件的能力,而文件w权限不行. inode:记录文件的 ...

  9. LinearLayout中间布局填充出现的问题

    线性布局如何中间填充,会挤掉他下面的布局,所以中间填充使用layout_weight属性.

  10. CUDA-GPU编程

    参考:http://blog.csdn.net/augusdi/article/details/12833235  第二节 新建NVIDIA项目: 新建项目及会生成一个简单的代码demo,计算矩阵的加 ...