优美的爆搜?KDtree学习

如果给你平面内一些点,让你求距离某一个指定点最近的点,应该怎么办呢?

O(n)遍历!

但是,在遍历的过程中,我们发现有一些点是永远无法更新答案的。

如果我们把这些点按照一定顺序整理起来,省略对不必要点的遍历,是不是可以降低时间复杂度呢?

这样的话,我们要用到的工具就是KDtree。

 

KDtree本质上是一颗BST(二叉搜索树),只不过每一层按照不同的维度分割,也就是说,一层划分x,一层划分y,交替进行。大概就是这样:

如果我们把他画在二维平面上的话,会发现KDtree实际上把一个矩形分割成了多个小矩形:

(我是来盗图的QAQ)

更新答案时,采用邻域搜索的方式。我们发现我们查询的点落在了某个小矩形内,我们用这个小矩形内的点去更新答案。然后进行回溯,看一下周围的矩形有没有可能存在更优答案,如果不可能的话,就不用搜索它了。

这样下来的复杂度最优是O(logn),随机数据介于O(logn)~O(sqrt(n))之间。如果是特意构造的数据,可以卡到O(n)(比如精度要求实数,给你一个圆,让你查询距离圆心最近的点)。

然而一般情况下KDtree比较好写,在考场上可以比较经济地拿到大部分分数,还是值得学习的。

关于代码实现,自己YY即可。反正我是脑补出来的。

 

例题:

BZOJ2716/2648:

KDtree查曼哈顿距离的板子,由于数据比较水所以直接插入可过,不需要考虑平衡性的问题。

代码自己YY。我的仅供参考(虽然我自行胡编的代码没什么参考价值QAQ)。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 using namespace std;
  7 const int maxn=1.5e6+1e2;
  8 const int inf=0x3f3f3f3f;
  9 
 10 int cmp,ans;
 11 struct Point {
 12     int d[2];
 13     friend bool operator < (const Point &a,const Point &b) {
 14         return a.d[cmp] < b.d[cmp];
 15     }
 16     int dis(const Point &o) const {
 17         int ret = 0;
 18         for(int i=0;i<2;i++)
 19             ret += abs( d[i] - o.d[i] );
 20         return ret;
 21     }
 22 }ps[maxn];
 23 
 24 int lson[maxn],rson[maxn],mi[maxn][2],mx[maxn][2];
 25 Point dv[maxn];
 26 int cnt;
 27 
 28 inline void update(int pos) {
 29     if( lson[pos] ) {
 30         for(int i=0;i<2;i++)
 31             mi[pos][i] = min( mi[pos][i] , mi[lson[pos]][i] ),
 32             mx[pos][i] = max( mx[pos][i] , mx[lson[pos]][i] );
 33     }
 34     if( rson[pos] ) {
 35         for(int i=0;i<2;i++)
 36             mi[pos][i] = min( mi[pos][i] , mi[rson[pos]][i] ),
 37             mx[pos][i] = max( mx[pos][i] , mx[rson[pos]][i] );
 38     }
 39 }
 40 inline void fill(int pos,const Point &p) {
 41     dv[pos] = p;
 42     for(int i=0;i<2;i++)
 43         mx[pos][i] = mi[pos][i] = p.d[i];
 44 }
 45 inline void build(int pos,int pl,int pr,int dir) {
 46     const int pmid = ( pl + pr ) >> 1;
 47     cmp = dir;
 48     nth_element(ps+pl,ps+pmid,ps+pr+1);
 49     fill(pos,ps[pmid]);
 50     if( pl < pmid ) build(lson[pos]=++cnt,pl,pmid-1,dir^1);
 51     if( pr > pmid ) build(rson[pos]=++cnt,pmid+1,pr,dir^1);
 52     update(pos);
 53 }
 54 inline void insert(int pos,Point np,int dir) {
 55     cmp = dir;
 56     if( np < dv[pos] ) {
 57         if( lson[pos] ) insert(lson[pos],np,dir^1);
 58         else {
 59             lson[pos] = ++cnt;
 60             fill(lson[pos],np);
 61         }
 62     } else {
 63         if( rson[pos] ) insert(rson[pos],np,dir^1);
 64         else {
 65             rson[pos] = ++cnt;
 66             fill(rson[pos],np);
 67         }
 68     }
 69     update(pos);
 70 }
 71 inline int dis(int pos,const Point &p) {
 72     int ret = 0;
 73     for(int i=0;i<2;i++)
 74         ret += max( p.d[i] - mx[pos][i] , 0 ) + max( mi[pos][i] - p.d[i] , 0 );
 75     return ret;
 76 }
 77 inline void query(int pos,const Point &p) {
 78     ans = min( ans , p.dis(dv[pos]) );
 79     int dl = lson[pos] ? dis(lson[pos],p) : inf;
 80     int dr = rson[pos] ? dis(rson[pos],p) : inf;
 81     if( dl < dr ) {
 82         if( dl < ans ) query(lson[pos],p);
 83         if( dr < ans ) query(rson[pos],p);
 84     } else {
 85         if( dr < ans ) query(rson[pos],p);
 86         if( dl < ans ) query(lson[pos],p);
 87     }
 88 }
 89 
 90 int main() {
 91     static int n,m;
 92     static Point p;
 93     
 94     scanf("%d%d",&n,&m);
 95     for(int i=1;i<=n;i++)
 96         scanf("%d%d",ps[i].d,ps[i].d+1);
 97     
 98     build(cnt=1,1,n,0);
 99     
100     for(int i=1,t;i<=m;i++) {
101         scanf("%d%d%d",&t,p.d,p.d+1);
102         if(t == 1) {
103             insert(1,p,0);
104         } else {
105             ans = inf;
106             query(1,p);
107             printf("%d\n",ans);
108         }
109     }
110     return 0;
111 }
View Code

 

BZOJ4066:

查询二维区间和。

本来这个题能够有多种做法,结果强制在线卡了cdq分治,20mb内存卡了树套树(什么你说你敢写?去写吧再见),其他一些奇奇怪怪的算法(分块线段树,分块splay之类的)并不是很容易实现。于是就只好KDtree了。

我们用KDtree上每一个节点去维护当前四边形的sum值,同时维护size。如果size过于不平衡了就进行重构(替罪羊树原理),同时手写内存池回收节点。

然而这样做并不能AC(怕不是我写搓了),需要在替罪羊重构的基础上判定一个修改次数,如果两次重构之间修改太少则不进行重构(否则不停地重构依旧TLE),另外你需要一个文件快读来保证AC。

另外如果这样写了仍不能AC,请注意调参,我用的是替罪羊的alpha设0.8,修改次数的lambda设1000,这样能够卡着50s的时限AC。

另外,如果实在TLE,那就弃了吧......

实在不明白为什么网上别人暴力重构和不重构能轻松AC。

代码:

  1 #pragma GCC optimize(3)
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cctype>
  5 using namespace std;
  6 const int maxn=2e5+1e1;
  7 const double alpha = 0.8;
  8    
  9 int cmp;
 10 struct Point {
 11     int d[2],val;
 12     friend bool operator < (const Point &a,const Point &b) {
 13         return a.d[cmp] < b.d[cmp];
 14     }
 15     friend bool operator == (const Point &a,const Point &b) {
 16         return a.d[0] == b.d[0] && a.d[1] == b.d[1];
 17     }
 18     Point operator += (const Point &x) {
 19         val += x.val;
 20         return *this;
 21     }
 22     inline void reset() {
 23         d[0] = d[1] = val = 0;
 24     }
 25 }ps[maxn],nv[maxn];
 26    
 27 int lson[maxn],rson[maxn],mi[maxn][2],mx[maxn][2],sum[maxn],siz[maxn];
 28 int reb,delta,root;
 29    
 30 namespace RamPool {
 31     int pool[maxn],top;
 32     inline void DelNode(int x) {
 33         lson[x] = rson[x] = 0;
 34         pool[++top] = x;
 35     }
 36     inline int NewNode() {
 37         return pool[top--];
 38     }
 39 }
 40    
 41 using RamPool::DelNode;using RamPool::NewNode;
 42    
 43 inline void update(int pos) {
 44     sum[pos] = nv[pos].val;
 45     if( lson[pos] ) {
 46         for(int i=0;i<2;i++)
 47             mi[pos][i] = min( mi[pos][i] , mi[lson[pos]][i] ),
 48             mx[pos][i] = max( mx[pos][i] , mx[lson[pos]][i] );
 49         sum[pos] += sum[lson[pos]];
 50     }
 51     if( rson[pos] ) {
 52         for(int i=0;i<2;i++)
 53             mi[pos][i] = min( mi[pos][i] , mi[rson[pos]][i] ),
 54             mx[pos][i] = max( mx[pos][i] , mx[rson[pos]][i] );
 55         sum[pos] += sum[rson[pos]];
 56     }
 57 }
 58 inline void fill(int pos,const Point &p) {
 59     nv[pos] = p , siz[pos] = 1;
 60     for(int i=0;i<2;i++)
 61         mi[pos][i] = mx[pos][i] = p.d[i];
 62     sum[pos] = p.val;
 63 }
 64 inline void build(int pos,int ll,int rr,int dir) {
 65     cmp = dir;
 66     const int mid = ( ll + rr ) >> 1;
 67     nth_element(ps+ll,ps+mid,ps+rr+1);
 68     fill(pos,ps[mid]); siz[pos] = rr - ll + 1;
 69     if( ll < mid ) build(lson[pos]=NewNode(),ll,mid-1,dir^1);
 70     if( rr > mid ) build(rson[pos]=NewNode(),mid+1,rr,dir^1);
 71     update(pos);
 72 }
 73 inline void recycle(int pos,int& pcnt) {
 74     if( lson[pos] ) recycle(lson[pos],pcnt);
 75     if( rson[pos] ) recycle(rson[pos],pcnt);
 76     ps[++pcnt] = nv[pos];
 77     DelNode(pos);
 78 }
 79 inline int rebuild(int pos,int dir) {
 80     reb = 1;
 81     int pcnt = 0;
 82     recycle(pos,pcnt);
 83     int ret = NewNode();
 84     build(ret,1,pcnt,dir);
 85     return ret;
 86 }
 87    
 88 inline int insert(int pos,int dir,const Point &p) {
 89     cmp = dir;
 90     if( !nv[pos].val ) {
 91         fill(pos,p);
 92         return pos;
 93     }
 94     if( p == nv[pos] ) {
 95         nv[pos] += p;
 96         sum[pos] += p.val;
 97         return pos;
 98     }
 99     ++siz[pos];
100     if( p < nv[pos] ) {
101         if( !lson[pos] ) lson[pos] = NewNode();
102         lson[pos] = insert(lson[pos],dir^1,p);
103         if( !reb && delta > 1000 && siz[lson[pos]] > (double) siz[pos] * alpha )
104             return rebuild(pos,dir);
105     } else {
106         if( !rson[pos] ) rson[pos] = NewNode();
107         rson[pos] = insert(rson[pos],dir^1,p);
108         if( !reb && delta > 1000 && siz[rson[pos]] > (double) siz[pos] * alpha )
109             return rebuild(pos,dir);
110     }
111     update(pos);
112     return pos;
113 }
114    
115 inline bool inside(const int &Insx,const int &Insy,const int &Intx,const int &Inty,const int &Osx,const int &Osy,const int &Otx,const int &Oty) {
116     return Osx <= Insx &&Intx <= Otx && Osy <= Insy &&Inty <= Oty;
117 }
118 inline bool outside(const int &Insx,const int &Insy,const int &Intx,const int &Inty,const int &Osx,const int &Osy,const int &Otx,const int &Oty) {
119     return Insx > Otx || Intx < Osx || Insy > Oty || Inty < Osy;
120 }
121 inline bool inside(const Point &p,const int &Osx,const int &Osy,const int &Otx,const int &Oty) {
122     return inside(p.d[0],p.d[1],p.d[0],p.d[1],Osx,Osy,Otx,Oty);
123 }
124 inline int query(int pos,const int &sx,const int &sy,const int &tx,int const &ty) {
125     if( outside(mi[pos][0],mi[pos][1],mx[pos][0],mx[pos][1],sx,sy,tx,ty) ) return 0;
126     if( inside(mi[pos][0],mi[pos][1],mx[pos][0],mx[pos][1],sx,sy,tx,ty) ) return sum[pos];
127     int ret = 0;
128     if( inside(nv[pos],sx,sy,tx,ty) ) ret += nv[pos].val;
129     if( lson[pos] ) ret += query(lson[pos],sx,sy,tx,ty);
130     if( rson[pos] ) ret += query(rson[pos],sx,sy,tx,ty);
131     return ret;
132 }
133    
134 inline void init() {
135     for(int i=1;i<maxn;i++)
136         DelNode(i);
137     root = NewNode();
138 }
139 
140 inline char nextchar() {
141     static char buf[1<<22],*st=buf+(1<<22),*ed=buf+(1<<22);
142     if( st == ed ) ed = buf + fread(st=buf,1,1<<22,stdin);
143     return st == ed ? -1 : *st++;
144 }
145 inline int getint() {
146     int ret = 0,ch;
147     while( !isdigit(ch=nextchar()) );
148     do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
149     return ret;
150 }
151    
152 int main() {
153     static int ope,lastans,sx,sy,tx,ty,xx,yy,num;
154     init();
155        
156     getint();
157     while( ( ope = getint() ) != 3 ) {
158         if( ope == 1 ) {
159             xx = getint() , yy = getint() , num = getint();
160             reb = 0 , ++delta;
161             xx ^= lastans , yy ^= lastans , num ^= lastans;
162             root = insert(root,0,(Point){xx,yy,num});
163         } else {
164             sx = getint() , sy = getint() , tx = getint() , ty = getint();
165             sx ^= lastans , sy ^= lastans , tx ^= lastans , ty ^= lastans;
166             printf("%d\n", lastans = query(root,sx,sy,tx,ty) );
167         }
168     }
169        
170     return 0;
171 }
View Code

 

Upd20180104:

其实那个TLE是我替罪羊重构写的姿势不对了,正确的姿势是找到最浅的不平衡点进行重构,不需要判断size的。虽然这样还是比暴力重构慢,但好在能稳稳地AC了QAQ。

代码:

  1 #pragma GCC optimize(3)
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cctype>
  5 using namespace std;
  6 const int maxn=2.5e5+1e2;
  7 const double alpha=0.8;
  8 
  9 int cmp;
 10 struct Point {
 11     int d[2],val;
 12     Point(){}
 13     Point(int xx,int yy,int vv) {d[0] = xx , d[1] = yy , val = vv;}
 14     friend bool operator < (const Point &a,const Point &b) {
 15         return a.d[cmp] < b.d[cmp];
 16     }
 17     friend bool operator == (const Point &a,const Point &b) {
 18         return a.d[0] == b.d[0] && a.d[1] == b.d[1];
 19     }
 20     Point operator += (const Point &r) {
 21         val += r.val;
 22         return *this;
 23     }
 24 }ps[maxn],dv[maxn];
 25 struct QNode {
 26     int mi[2],mx[2];
 27     QNode(int Mix,int Miy,int Mxx,int Mxy) {
 28         mi[0] = Mix , mi[1] = Miy , mx[0] = Mxx , mx[1] = Mxy;
 29     }
 30 };
 31 int lson[maxn],rson[maxn],siz[maxn],mi[maxn][2],mx[maxn][2],sum[maxn];
 32 int root,rebp,rebfa,rebdir;
 33 
 34 namespace RamPool {
 35     int pool[maxn],top;
 36     inline void DelNode(int x) {
 37         siz[x] = lson[x] = rson[x] = 0;
 38         pool[++top] = x;
 39     }
 40     inline int NewNode() {
 41         return pool[top--];
 42     }
 43 }
 44 using RamPool::DelNode; using RamPool::NewNode;
 45 
 46 inline void fill(int pos,const Point &p) {
 47     dv[pos] = p , sum[pos] = p.val , siz[pos] = 1;
 48     for(int i=0;i<2;i++)
 49         mi[pos][i] = mx[pos][i] = p.d[i];
 50 }
 51 inline void coreupdate(const int &fa,const int &son) {
 52     sum[fa] += sum[son] , siz[fa] += siz[son];
 53     for(int i=0;i<2;i++)
 54         mi[fa][i] = min( mi[fa][i] , mi[son][i] ) ,
 55         mx[fa][i] = max( mx[fa][i] , mx[son][i] );
 56 }
 57 inline void update(int pos) {
 58     sum[pos] = dv[pos].val , siz[pos] = 1;
 59     if( lson[pos] )
 60         coreupdate(pos,lson[pos]);
 61     if( rson[pos] )
 62         coreupdate(pos,rson[pos]);
 63 }
 64 inline void build(int pos,int ll,int rr,int dir) {
 65     cmp = dir;
 66     const int mid = ( ll + rr ) >> 1;
 67     nth_element(ps+ll,ps+mid,ps+rr+1);
 68     fill(pos,ps[mid]);
 69     if( ll < mid ) build(lson[pos]=NewNode(),ll,mid-1,dir^1);
 70     if( rr > mid ) build(rson[pos]=NewNode(),mid+1,rr,dir^1);
 71     update(pos);
 72 }
 73 inline void recycle(int pos,int& pcnt) {
 74     if( lson[pos] ) recycle(lson[pos],pcnt);
 75     if( rson[pos] ) recycle(rson[pos],pcnt);
 76     ps[++pcnt] = dv[pos];
 77     DelNode(pos);
 78 }
 79 inline int rebuild(int pos,int dir) {
 80     int pcnt = 0;
 81     recycle(pos,pcnt);
 82     int ret = NewNode();
 83     build(ret,1,pcnt,dir);
 84     return ret;
 85 }
 86 inline void insert(int pos,int dir,const Point &p) {
 87     cmp = dir;
 88     if( !dv[pos].val ) {
 89         fill(pos,p);
 90         return;
 91     }
 92     if( dv[pos] == p ) {
 93         dv[pos] += p , sum[pos] += p.val;
 94         return;
 95     }
 96     if( p < dv[pos] ) {
 97         if( !lson[pos] ) lson[pos] = NewNode();
 98         insert(lson[pos],dir^1,p);
 99         update(pos);
100         if( siz[lson[pos]] > siz[pos] * alpha )  rebp = pos , rebdir = dir , rebfa = 0;
101         else if( lson[pos] == rebp ) rebfa = pos;
102     } else {
103         if( !rson[pos] ) rson[pos] = NewNode();
104         insert(rson[pos],dir^1,p);
105         update(pos);
106         if( siz[rson[pos]] > siz[pos] * alpha ) rebp = pos , rebdir = dir , rebfa = 0;
107         else if( rson[pos] == rebp ) rebfa = pos;
108     }
109 }
110 
111 inline bool inside(const int* mi,const int* mx,const QNode &q) {
112     return q.mi[0] <= mi[0] && mx[0] <= q.mx[0] && q.mi[1] <= mi[1] && mx[1] <= q.mx[1];
113 }
114 inline bool inside(const Point &p,const QNode &q) {
115     return inside(p.d,p.d,q);
116 }
117 inline bool inside(const int &pos,const QNode &q) {
118     return inside(mi[pos],mx[pos],q);
119 }
120 inline bool outside(const int* mi,const int* mx,const QNode &q) {
121     return mx[0] < q.mi[0] || q.mx[0] < mi[0] || mx[1] < q.mi[1] || q.mx[1] < mi[1];
122 }
123 inline bool outside(const int &pos,const QNode &q) {
124     return outside(mi[pos],mx[pos],q);
125 }
126 inline int query(int pos,const QNode &q) {
127     if( outside(pos,q) ) return 0;
128     if( inside(pos,q) ) return sum[pos];
129     int ret = 0;
130     if( inside(dv[pos],q) ) ret = dv[pos].val;
131     if( lson[pos] ) ret += query(lson[pos],q);
132     if( rson[pos] ) ret += query(rson[pos],q);
133     return ret;
134 }
135 
136 inline void init() {
137     for(int i=maxn-1;i;i--)
138         DelNode(i);
139     root = NewNode();
140 }
141 inline void rebuild() {
142     if( !rebfa ) root = rebuild(root,0);
143     else if( rebp == lson[rebfa] ) lson[rebfa] = rebuild(rebp,rebdir);
144     else rson[rebfa] = rebuild(rebp,rebdir);
145 }
146 
147 inline char nextchar() {
148     static char buf[1<<21],*st=buf+(1<<21),*ed=buf+(1<<21);
149     if( st == ed ) ed = buf + fread(st=buf,1,1<<21,stdin);
150     return st != ed ? *st++ : -1;
151 }
152 inline int getint() {
153     int ret = 0 , ch;
154     while( !isdigit(ch=nextchar()) );
155     do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
156     return ret;
157 }
158 
159 int main() {
160     static int ope,xx,yy,add,sx,sy,tx,ty,lastans;
161     init();
162     getint();
163     while( ( ope = getint() ) != 3 ) {
164         if( ope == 1 ) {
165             xx = getint()^lastans , yy = getint()^lastans , add = getint()^lastans;
166             rebp = rebfa = rebdir = 0;
167             insert(root,0,Point(xx,yy,add));
168             if( rebp ) rebuild();
169         } else if( ope == 2 ) {
170             sx = getint()^lastans , sy = getint()^lastans , tx = getint()^lastans , ty = getint()^lastans;
171             printf("%d\n", lastans = query( root , QNode(sx,sy,tx,ty) ) );
172         }
173     }
174     
175     return 0;
176 }
View Code

 

另外KDtree还有一道水题:

BZOJ2850:

让你求平面内ax+by<=c的点的权值和。没有插入只有查询……KDtree随便做一下就好了,看一看当前块是不是全部包含在可行范围内,如果全部包含则返回sum,如果全部不包含则返回0,否则递归查询子树。

这样的复杂度大概是log级的,考虑每次分成4块,最多往下递归3块,这样是log级的。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define lli long long int
 6 #define debug cout
 7 using namespace std;
 8 const int maxn=1e6+1e2;
 9 
10 int cmp;
11 struct Point {
12     lli d[2],h;
13     friend bool operator < (const Point &a,const Point &b) {
14         return a.d[cmp] < b.d[cmp];
15     }
16     inline lli f(int a,int b) const {
17         return a * d[0] + b * d[1];
18     }
19 }ps[maxn],dv[maxn];
20 
21 int lson[maxn],rson[maxn],cnt;
22 lli mx[maxn][2],mi[maxn][2],sum[maxn];
23 lli c;
24 
25 inline lli f(lli x,lli y,int a,int b) {
26     return a * x + b * y;
27 }
28 
29 inline void update(int pos) {
30     if( lson[pos] ) {
31         for(int i=0;i<2;i++)
32             mi[pos][i] = min( mi[pos][i] , mi[lson[pos]][i] ),
33             mx[pos][i] = max( mx[pos][i] , mx[lson[pos]][i] );
34         sum[pos] += sum[lson[pos]];
35     }
36     if( rson[pos] ) {
37         for(int i=0;i<2;i++)
38             mi[pos][i] = min( mi[pos][i] , mi[rson[pos]][i] ),
39             mx[pos][i] = max( mx[pos][i] , mx[rson[pos]][i] );
40         sum[pos] += sum[rson[pos]];
41     }
42 }
43 inline void fill(int pos,const Point &p) {
44     dv[pos] = p;
45     for(int i=0;i<2;i++)
46         mx[pos][i] = mi[pos][i] = p.d[i];
47     sum[pos] = p.h;
48 }
49 inline void build(int pos,int ll,int rr,int dir) {
50     cmp = dir;
51     const int mid = ( ll + rr ) >> 1;
52     nth_element(ps+ll,ps+mid,ps+rr+1);
53     fill(pos,ps[mid]);
54     if( ll < mid ) build(lson[pos]=++cnt,ll,mid-1,dir^1);
55     if( rr > mid ) build(rson[pos]=++cnt,mid+1,rr,dir^1);
56     update(pos);
57 }
58 inline int judge(int pos,int a,int b) {
59     return ( f(mx[pos][0],mx[pos][1],a,b) < c ) + ( f(mx[pos][0],mi[pos][1],a,b) < c ) + 
60            ( f(mi[pos][0],mx[pos][1],a,b) < c ) + ( f(mi[pos][0],mi[pos][1],a,b) < c ) ;
61 }
62 inline lli query(int pos,int a,int b) {
63     lli ret = 0;
64     if( dv[pos].f(a,b) < c )
65         ret += dv[pos].h;
66     if( lson[pos] ) {
67         int jl = judge(lson[pos],a,b);
68         if( jl == 4 ) ret += sum[lson[pos]];
69         else if( jl ) ret += query(lson[pos],a,b);
70     }
71     if( rson[pos] ) {
72         int jr = judge(rson[pos],a,b);
73         if( jr == 4 ) ret += sum[rson[pos]];
74         else if( jr ) ret += query(rson[pos],a,b);
75     }
76     return ret;
77 }
78 
79 int main() {
80     static int n,m;
81     scanf("%d%d",&n,&m);
82     for(int i=1;i<=n;i++)
83         scanf("%lld%lld%lld",ps[i].d,ps[i].d+1,&ps[i].h);
84     
85     build(cnt=1,1,n,0);
86     
87     for(int i=1,a,b;i<=m;i++) {
88         scanf("%d%d%lld",&a,&b,&c);
89         printf("%lld\n",query(1,a,b));
90     }
91     return 0;
92 }
View Code

 

posted @ 2018-01-13 11:51  Cmd2001  阅读(344)  评论(0编辑  收藏  举报