// algorithms to compute distances between mycells, and an implementation of tally counter namespace dhrg { int segmentcount; struct qtybox { int minv, maxv; int qty[BOXSIZE]; int& operator [] (int i) { if(i>=BOXSIZE) throw hr_exception("not enough memory reserved -- increase BOXSIZE constant"); return qty[i]; } qtybox() { for(int i=0; ibuild(); pright->build(); segment *c1 = pleft->byleft[setid]; while(c1) { if(c1->right == pright) { return c1; } c1 = c1 -> nextleft; } if(!docreate) return c1; segment *p = new segment; p->left = pleft; p->right = pright; p->nextleft = pleft->byleft[setid]; pleft->byleft[setid] = p; p->nextright = pright->byright[setid]; pright->byright[setid] = p; p->nextchild = NULL; p->firstchild = NULL; if(pleft->leftparent) { p->parent = getsegment(pleft->leftparent, pright->rightparent, setid); p->nextchild = p->parent->firstchild; p->parent->firstchild = p; } else p->parent = NULL; #ifdef LONG_BRACKETS if(pleft != pright) { pleft = pleft->grightsibling(); int slen = 0; while(pleft != pright) { segmentlist *n = new segmentlist; slen++; n->s = p; n->next = pleft->bracketing; pleft->bracketing = n; pleft = pleft->grightsibling(); } if(slen > 10) throw hr_exception("bad bracket"); } #endif return p; } ll tally[MAXDIST]; ll *whichtally = tally; vector acknowledged; void tallybox(qtybox& box, int d, int mul) { for(int i=box.minv; iseen == -1) { p->seen = d; acknowledged.emplace_back(p); } else if(p->seen > d) p->seen = d; } void acknowledgments(int mul) { for(segment* p: acknowledged) { tallybox(p->qty, p->seen, mul); segment *p2 = p->parent; int dist = 1; while(p2) { if(p2->seen != -1) { tallybox(p->qty, p2->seen+dist, -mul); break; } p2=p2->parent; dist++; } p->seen = -1; } acknowledged.clear(); } void trim(qtybox& b) { while(b.minv < b.maxv && !b[b.minv]) b.minv++; if(b.minv == b.maxv) b.minv = BOXSIZE, b.maxv = 0; else while(!b[b.maxv-1]) b.maxv--; } void add_to_set(mycell *c, int mul, int setid) { // assume mul does not equal 0 ! segment *p = getsegment(c, c, setid); int d = 0; while(p) { p->qty[d] += mul; if(p->qty[d]) { p->qty.minv = min(p->qty.minv, d); p->qty.maxv = max(p->qty.maxv, d+1); } else trim(p->qty); d++; p = p->parent; } } int segmentdist(segment *p1, segment *p2, int d); void build_ack(mycell *c, int setid) { segment *p = getsegment(c, c, setid); int d = 0; #ifdef LONG_BRACKETS segmentlist *brackets = c->bracketing; while(brackets) { acknowledge(brackets->s, 0); brackets = brackets->next; } #else acknowledge(getsegment(c->gleftsibling(), c->grightsibling(), setid, false), 0); // larger! #endif while(p) { if(p->left != p->right) { mycell *cc = p->left->grightsibling(); while(cc != p->right) { acknowledge(getsegment(cc, cc, setid, false), d); cc = cc->grightsibling(); } } int sl = cgi.expansion->sibling_limit; mycell *mright = p->right; mycell *mright0 = mright; for(int u=0; u<=sl; u++) { mright->build(); segment *mrightbyleft = mright->byleft[setid]; while(mrightbyleft) { if(u == 3 && p->right->rightparent == mright->leftparent) acknowledge(mrightbyleft, d+2); else if(u > 3) acknowledge(mrightbyleft, segmentdist(getsegment(mright0, mright0, setid), mrightbyleft, d)); else acknowledge(mrightbyleft, d+u); mrightbyleft = mrightbyleft->nextleft; } mright=mright->grightsibling(); } mycell *mleft = p->left; mycell *mleft0 = mleft; for(int u=0; u<=sl; u++) { mleft->build(); segment *mleftbyright = mleft->byright[setid]; while(mleftbyright) { if(u == 3 && p->left -> leftparent == mleft->rightparent) acknowledge(mleftbyright, d+2); else if(u > 3) acknowledge(mleftbyright, segmentdist(mleftbyright, getsegment(mleft0, mleft0, setid), d)); else acknowledge(mleftbyright, d+u); mleftbyright = mleftbyright->nextright; } mleft=mleft->gleftsibling(); } // go forth d++; p = p->parent; } } void add_to_tally(mycell *c, int mul, int setid) { build_ack(c, setid); acknowledgments(mul); } bool is_insegment(mycell *c, segment *p) { mycell *p1 = p->left; mycell *p2 = p->right; while(true) { if(c == p1) return true; if(p1 == p2) return false; p1 = p1->grightsibling(); } } int segmentdist(segment *p1, segment *p2, int d) { if(p1->left == p1->right && is_insegment(p1->left, p2)) return d; if(p2->left == p2->right && is_insegment(p2->left, p1)) return d; int best = 1000000; while(true) { if(d >= best) return best; mycell *mright; int sl = cgi.expansion->sibling_limit; mright = p1->right; for(int u=0; u<=sl; u++) { mright->build(); if(mright == p2->left) best = min(best, d+u); mright = mright->grightsibling(); } mright = p2->right; for(int u=0; u<=sl; u++) { mright->build(); if(mright == p1->left) best = min(best, d+u); mright = mright->grightsibling(); } p1 = p1->parent; p2 = p2->parent; d += 2; } } int quickdist(mycell *c1, mycell *c2, int setid=0) { int d = 0; c1->build(); c2->build(); int d1 = c1->lev; int d2 = c2->lev; segment *p1 = getsegment(c1, c1, setid); segment *p2 = getsegment(c2, c2, setid); while(d1>d2) { p1 = p1->parent; d1--; d++; } while(d2>d1) { p2 = p2->parent; d2--; d++; } return segmentdist(p1, p2, d); } }