非递归ZKW线段树完全模板

来源:互联网 发布:linux yum配置本地源 编辑:程序博客网 时间:2024/06/07 18:16

经过一番刷题,终于用非递归线段树搞定线段树的基本问题,ZKW神牛的《统计的力量》带我入门,尽管后面一大堆都看不懂……言归正传,贴模板,顺便为以后区域赛做准备——

int M, T;/*M和T都是非递归线段树里面的关键变量,M的含义同《统计的力量》中的M含义相同,T是M的高度计算公式:for (M = T = 1; M < n + 2; M <<= 1, T++);其中n是元素个数*/struct node{/*放一个结点需要维护的信息*/} g[N << 2];//节点数*4,也可以先算出M最大值,然后开M+M数组省一个常数void dn(int f)//等同push_down,不过是一次性将相关的标记下传,不像递归那样每次只下传一层{for (int i = T - 1; i > 0; i--){int c = f >> i;int l = c << 1, r = l ^ 1;//这里就等同push_down了,用父亲节点c更新其左右儿子}}void up(int c)//等同push_up,与其区别类比dn与push_down{for (c >>= 1; c; c >>= 1){   //等同push_up}}void add(int l, int r, int d){l += M - 1, r += M + 1;dn(l),dn(r);for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1){//}if (t & 1){//}}up(l),up(r);}int Q(int l, int r){int ans = 0;l += M - 1, r += M + 1;dn(l),dn(r);for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1){//}if (t & 1){//}}return ans;}
理解dn与up之后,对应递归的写法,直接写非递归就可以了,进行区间操作与统计区间信息都类似代码中的add与Q,有的甚至可以只有dn没有up(比如区间染色),或者只有up没有dn(比如扫描线),经个人刷题经验,一般只有维护区间和才需要dn与up同时上,至于二维线段树,也就把楼上操作用结构体tree封装,然后……就没然后了,扫描线就普通的区间加操作而已,至于多个标记复合,要自己开脑洞我就不多说了

其实,确实,非递归能做的,递归也能做,至于理解方面,有人觉得递归容易理解,我却更容易理解非递归,可能由于百度上面关于非递归线段树代码资料太少,所以大家都去学递归的,因为确实暂时没发现递归做不到而非递归做得到的线段树问题,我学非递归也只是实在看不懂递归,但你们要是知道我10天时间就用非递归线段树解决单点更新,区间更新(区间加与区间染色),区间合并,扫描线,二维线段树等问题,同时现在打非递归线段树半小时打出来是很正常的速度(表示是二指禅而且不会盲打),你们就知道我为何对非递归线段树如此趋从了……顺便说句,我说的是打出框架,不代表立马能解决,像标记复合还是要想段时间的。

最后,再重复一次非递归的优势吧,尽管《统计的力量》已经有说了一些,至于缺点……《统计的力量 》也说的很清楚了→_→不过话说除了空间大一个常数还有啥缺点?

优点:

代码短容易打,看我半小时打出框架就知道了,当然,这点论文也有说

易调试,这点是基于我队友曾经对线段树调试调了整个比赛都调不出的经历我才敢说的,因为确实非递归要调试很容易,如果有人觉得递归线段树调试也不难,我也没法反对,毕竟我不懂

最后的最后,差点忘了,还有一份代码,可持久化线段树非递归版(尽管多了一个常数,但毕竟也AC了嘛→_→不过我觉得那是出题人没卡我,因为那常数好像不小)

//POJ2104 K-th Number//http://poj.org/problem?id=2104#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <vector>#define mp(x,y) make_pair(x,y)using namespace std;const int N = 100000;const int inf = 0x3f3f3f3f;int a[N + 10];int b[N + 10];int M;int lq, rq;vector<pair<int, int> > s[N * 22];void add(int id, int cur){cur += M;int lat = 0;if (s[cur].size())lat = s[cur][s[cur].size() - 1].second;s[cur].push_back(mp(id, ++lat));for (cur >>= 1; cur; cur >>= 1){int l = 0;if (s[cur << 1].size())l = s[cur << 1][s[cur << 1].size() - 1].second;int r = 0;if (s[cur << 1 | 1].size())r = s[cur << 1 | 1][s[cur << 1 | 1].size() - 1].second;s[cur].push_back(mp(id, l + r));}}int Q(int id, int k){if (id >= M) return id - M;int l = id << 1, r = l ^ 1;int ll = lower_bound(s[l].begin(), s[l].end(), mp(lq, inf)) - s[l].begin() - 1;int rr = lower_bound(s[l].begin(), s[l].end(), mp(rq, inf)) - s[l].begin() - 1;int kk = 0;if (rr >= 0)kk = s[l][rr].second;if (ll >= 0)kk = s[l][rr].second - s[l][ll].second;if (kk < k)return Q(r, k - kk);return Q(l, k);}int main(){int n, m;while (~scanf("%d%d", &n, &m)){for (int i = 0; i < n; i++){scanf("%d", a + i);b[i] = a[i];}sort(b, b + n);int nn = unique(b, b + n) - b;for (M = 1; M < nn; M <<= 1);for (int i = 1; i < M + M; i++){s[i].clear();//s[i].push_back(mp(0, 0));}for (int i = 0; i < n; i++){int id = lower_bound(b, b + nn, a[i]) - b;add(i + 1, id);}while (m--){int k;scanf("%d %d %d", &lq, &rq, &k);lq--;int x = Q(1, k);printf("%d\n", b[x]);}}return 0;}

 

新增封装,含区间染色与区间加

const int N = 1e5;struct node{int sum, d, v;int l, r;void init(){d = 0;v = -1;}void cb(node ls, node rs){sum = ls.sum + rs.sum;l = ls.l, r = rs.r;}int len(){return r - l + 1;}void V(int x){sum = len() * x;d = 0;v = x;}void D(int x){sum += len() * x;d += x;}};struct tree{int m, h;node g[N << 2];void init(int n){for (m = h = 1; m < n + 2; m <<= 1, h++);int i = 0;for (; i <= m; i++){g[i].init();g[i].sum = 0;}for (; i <= m + n; i++){g[i].init();scanf("%d", &g[i].sum);g[i].l = g[i].r = i - m;}for (; i < m + m; i++){g[i].init();g[i].sum = 0;g[i].l = g[i].r = i - m;}for (i = m - 1; i > 0; i--)g[i].cb(g[i << 1], g[i << 1 | 1]);}void dn(int x){for (int i = h - 1; i > 0; i--){int f = x >> i;if (g[f].v != -1){g[f << 1].V(g[f].v);g[f << 1 | 1].V(g[f].v);}if (g[f].d){g[f << 1].D(g[f].d);g[f << 1 | 1].D(g[f].d);}g[f].v = -1;g[f].d = 0;}}void up(int x){for (x >>= 1; x; x >>= 1){if (g[x].v != -1)continue;int d = g[x].d;g[x].d = 0;g[x].cb(g[x << 1], g[x << 1 | 1]);g[x].D(d);}}void update(int l, int r, int x, int o){l += m - 1, r += m + 1;dn(l), dn(r);for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1){if (o)g[s ^ 1].V(x);elseg[s ^ 1].D(x);}if (t & 1){if (o)g[t ^ 1].V(x);elseg[t ^ 1].D(x);}}up(l), up(r);}int Q(int l, int r){int ans = 0;l += m - 1, r += m + 1;dn(l), dn(r);for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1)ans += g[s ^ 1].sum;if (t & 1)ans += g[t ^ 1].sum;}return ans;}};

POJ2155 二维非递归线段树解法

#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <vector>#include <iostream>using namespace std;const int W = 1000;int m;struct tree{int d[W << 2];void o(){for (int i = 1; i < m + m; i++)d[i] = 0;}void Xor(int l, int r){l += m - 1, r += m + 1;for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1)d[s ^ 1] ^= 1;if (t & 1)d[t ^ 1] ^= 1;}}} g[W << 2];void chu(){for (int i = 1; i < m + m; i++)g[i].o();}void Xor(int lx, int ly, int rx, int ry){lx += m - 1, rx += m + 1;for (int s = lx, t = rx; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1)g[s ^ 1].Xor(ly, ry);if (t & 1)g[t ^ 1].Xor(ly, ry);}}int Q(int x, int y){int ans = 0;for (int xx = x + m; xx; xx >>= 1){for (int yy = y + m; yy; yy >>= 1){ans ^= g[xx].d[yy];}}return ans;}int main(){int T;cin >> T;int fl = 0;while (T--){if (fl){printf("\n");}fl = 1;int N, M;cin >> N >> M;for (m =  1; m < N + 2; m <<= 1);chu();while (M--){char o[4];scanf("%s", o);if (*o == 'Q'){int x, y;scanf("%d%d", &x, &y);printf("%d\n", Q(x, y));}else{int lx, ly, rx, ry;scanf("%d%d%d%d", &lx, &ly, &rx, &ry);Xor(lx, ly, rx, ry);}}}return 0;}
HDU1828非递归扫描线

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#include <iostream>using namespace std;const int Z = 10000 + 1;struct line{int x, yl, yr , o;line() {}line(int x, int yl, int yr, int o): x(x), yl(yl), yr(yr), o(o) {}bool operator < (const line& c)const{return x < c.x || (x == c.x && o > c.o);}};struct node{int l, r, c, num, S;bool lb, rb;void mem(int L, int R){l = L, r = R;c = num = S = 0;lb = rb = false;}void cb(node a, node b){l = a.l, r = b.r;lb = a.lb, rb = b.rb;num = a.num + b.num - 2 * (a.rb && b.lb);S = a.S + b.S;}};int m;vector<line>L;node g[Z << 3];void get(int x){if (g[x].c){g[x].S = g[x].r - g[x].l;g[x].num = 2;g[x].lb = g[x].rb = true;}else if (g[x].r - g[x].l == 1){g[x].S = 0;g[x].num = 0;g[x].lb = g[x].rb = false;}else{g[x].cb(g[x << 1], g[x << 1 | 1]);}}void up(int x){for (x >>= 1; x; x >>= 1)get(x);}void add(int l, int r, int d){l += m - 1;r += m + 1;for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1){g[s ^ 1].c += d;get(s ^ 1);}if (t & 1){g[t ^ 1].c += d;get(t ^ 1);}}up(l);up(r);}void chu(){for (int i = m; i < m + m; i++){g[i].mem(i - m - 1, i - m);}for (int i = m - 1; i > 0; i--){g[i].cb(g[i << 1], g[i << 1 | 1]);}}int main(){int n;for (m = 1; m < Z * 2; m <<= 1);while (cin >> n){chu();L.clear();for (int i = 0; i < n; i++){int a, b, c, d;scanf("%d%d%d%d", &a, &b, &c, &d);int xl = min(a, c), xr = max(a, c);int yl = min(b, d), yr = max(b, d);L.push_back(line(xl, yl, yr, 1));L.push_back(line(xr, yl, yr, -1));}sort(L.begin(), L.end());int ans = 0;int lat = 0;for (int i = 0; i < L.size(); i++){if (i)ans += g[1].num * (L[i].x - L[i - 1].x);add(L[i].yl + Z, L[i].yr + Z - 1, L[i].o);ans += abs(lat - g[1].S);lat = g[1].S;}cout << ans << endl;}return 0;}


还是扫描线,但多了离散化(HDU1542)

#include <algorithm>#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <cmath>using namespace std;const int N = 111;int n;vector<double> y;struct node{double s;int c;int l, r;void chu(double ss, int cc, int ll, int rr){s =  ss;c = cc;l = ll, r = rr;}double len(){return y[r] - y[l - 1];}} g[N << 4];int M;void init(int n){for (M = 1; M < n + 2; M <<= 1);g[M].chu(0, 0, 1, 1);for (int i = 1; i <= n; i++)g[i + M].chu(0, 0, i, i);for (int i = n + 1; i < M; i++)g[i + M].chu(0, 0, n, n);for (int i = M - 1; i > 0; i--)g[i].chu(0, 0, g[i << 1].l, g[i << 1 | 1].r);}struct line{double x, yl, yr;int d;line() {}line(double x, double yl, double yr, int dd): x(x), yl(yl), yr(yr), d(dd) {}bool operator < (const line &cc)const{return x < cc.x || (x == cc.x && d > cc.d);}};vector<line>L;void one(int x){if (x >= M){g[x].s = g[x].c ? g[x].len() : 0;return;}g[x].s = g[x].c ? g[x].len() : g[x << 1].s + g[x << 1 | 1].s;}void up(int x){for (; x; x >>= 1)one(x);}void add(int l, int r, int d){if (l > r)return;l += M - 1, r += M + 1;for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1){if (~s & 1){g[s ^ 1].c += d;one(s ^ 1);}if (t & 1){g[t ^ 1].c += d;one(t ^ 1);}}up(l);up(r);}double sol(){y.clear();L.clear();for (int i = 0; i < n; i++){double lx, ly, rx, ry;scanf("%lf %lf %lf %lf", &lx, &ly, &rx, &ry);L.push_back(line(lx, ly, ry, 1));L.push_back(line(rx, ly, ry, -1));y.push_back(ly);y.push_back(ry);}sort(y.begin(), y.end());y.erase(unique(y.begin(), y.end()), y.end());init(y.size());sort(L.begin(), L.end());n = L.size() - 1;double ans = 0;for (int i = 0; i < n; i++){int l = upper_bound(y.begin(), y.end(), L[i].yl + 1e-8) - y.begin();int r = upper_bound(y.begin(), y.end(), L[i].yr + 1e-8) - y.begin() - 1;add(l, r, L[i].d);ans += g[1].s * (L[i + 1].x - L[i].x);}return ans;}int main(){int ca = 1;while (cin >> n && n){printf("Test case #%d\nTotal explored area: %.2f\n\n", ca++, sol());}return 0;}



0 0
原创粉丝点击