hdu 4747 Mex
这道题明显考的是思维方式,线段树作为成段更新求和的辅助。for i = 1:n
x(i) = 从1到i区间内符合题意的值
endfor i = n:1
y(i) = num(i)下次出现的最近位置
endres=x(1:n)for cur = 1:n-1
更新cur+1:y[cur]-1的值,这里用到线段树
res+=结果(cur+1:n)
end#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> using namespace std; /* http://acm.hdu.edu.cn/showproblem.php?pid=4747 */ const int MAXN = 200010; const int INF = MAXN<<2; const int ZERO = -1; #define LL __int64 #define ll (root<<1) #define rr (ll|1) #define lson l,m,ll #define rson m+1,r,rr #define mid m=(l+r)>>1 int n, cur; int data[MAXN], num[MAXN], next[MAXN], pp[MAXN]; struct _MEX { int mx, mn; LL sum; int sz; }mex[MAXN*3]; void pushUP(int l, int r, int m, int root) { mex[root].sum = 0; mex[root].mx = ZERO; mex[root].mn = INF; int z = ll, y = rr; if (m >= cur) { mex[root].sum += mex[z].sum; mex[root].mx = max(mex[root].mx, mex[z].mx); mex[root].mn = min(mex[root].mn, mex[z].mn); } if (r >= cur) { mex[root].sum += mex[y].sum; mex[root].mx = max(mex[root].mx, mex[y].mx); mex[root].mn = min(mex[root].mn, mex[y].mn); } } void pushDOWN(int l, int r, int m, int root) { if (mex[root].sz == -1) return; int z = ll, y = rr; if (m >= cur) { int k = max(cur, l); mex[z].sum = (LL)(m-k+1) * (LL)mex[root].sz; mex[z].mx = mex[z].mn = mex[root].sz; mex[z].sz = mex[root].sz; } if (r >= cur) { int k = max(cur, m+1); mex[y].sum = (LL)(r-k+1) * (LL)mex[root].sz; mex[y].mx = mex[y].mn = mex[root].sz; mex[y].sz = mex[root].sz; } mex[root].sz = -1; } void build(int l, int r, int root) { mex[root].sz = -1; if (l == r) { mex[root].mx = mex[root].mn = data[l]; mex[root].sum = data[l]; return; } int mid; build(lson); build(rson); pushUP(l,r,m,root); } void change(int c, int x, int y, int l, int r, int root) { if (x <= l && y >= r ) { if (c < mex[root].mn) { mex[root].mx = mex[root].mn = c; mex[root].sz = c; int k = max(cur, l); mex[root].sum = (LL)(r-k+1) * c; return; } if (c > mex[root].mx) { if (l >= cur) return; } } int mid; pushDOWN(l,r,m,root); if (x <= m && m >= cur) { change(c,x,y,lson); } if (y > m && r >= cur) { change(c,x,y,rson); } pushUP(l,r,m,root); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif while (scanf("%d", &n)!=EOF && n) { for (int i = 0; i< n; ++i) { scanf("%d", &num[i]); if (num[i] > n) num[i] = n+1; } int c = 0; memset(next, 0, sizeof next); for (int i = 0; i< n; ++i) { next[num[i]] = 1; while (next[c]) c++; data[i] = c; } memset(pp, -1, sizeof pp); for (int i = n-1; i>= 0; --i) { next[i] = pp[num[i]]; pp[num[i]] = i; } cur = 0; build(0,n-1, 1); LL res = mex[1].sum; for (int i = 0; i < n-1; ++i) { cur = i+1; if (num[i] != num[i+1]) { if (next[i] == -1) change(num[i], i+1, n-1, 0, n-1, 1); else change(num[i], i+1, next[i]-1, 0, n-1, 1); } else { change(INF,i+1,i+1,0,n-1,1); } res += mex[1].sum; } printf("%I64d\n", res); } return 0; }
hdu 3642 Get The Treasury
利用线段树求区间重叠,原理上和 hdu 1255 差不多。。。加入点优化,Node 中的 one ,two, more 表示 大于等于 1,2,3 次,这样在段汇总的时候就可以省去一些步骤#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> using namespace std; /* http://acm.hdu.edu.cn/showproblem.php?pid=3642 */ const int MAXN = 3000; #define LL __int64 #define ll (root<<1) #define rr (ll|1) #define lson l,mm,ll #define rson mm,r,rr #define mid mm=(l+r)>>1 struct mFace { int y; int x1, x2, z1, z2; int sz; mFace(){} mFace(int _y, int _x1, int _x2, int _z1, int _z2, int _sz) :y(_y), x1(_x1), x2(_x2), z1(_z1), z2(_z2), sz(_sz) {} bool operator < (const mFace & a) const { return y < a.y; } }mf[MAXN], tp[MAXN]; struct Node { int one, two, more; int c, x1, x2, y; // cnt; range x1, x2; y int l, r; // index int len; void init() { one = two = more = 0; c = 0; len = x2-x1; } }nd[MAXN*3]; int xx[MAXN], zz[MAXN]; void build (int l, int r, int root) { nd[root].x1 = xx[l]; nd[root].x2 = xx[r]; nd[root].l = l, nd[root].r = r; nd[root].init(); if (l+1 == r) return; int mid; build(lson); build(rson); } void pushUP(int root) { int l = nd[root].l, r = nd[root].r; if (nd[root].c == 0) { if (l+1 == r) { nd[root].one = nd[root].two = nd[root].more = 0; } else { nd[root].one = nd[ll].one + nd[rr].one; nd[root].two = nd[ll].two + nd[rr].two; nd[root].more = nd[ll].more + nd[rr].more; } } else if (nd[root].c == 1) { nd[root].one = nd[root].len; if (l + 1 == r) { nd[root].two = nd[root].more = 0; } else { nd[root].two = nd[ll].one + nd[rr].one; nd[root].more = nd[ll].two + nd[rr].two; } } else if (nd[root].c == 2) { nd[root].one = nd[root].two = nd[root].len; if (l+1 == r) { nd[root].more = 0; } else { nd[root].more = nd[ll].one + nd[rr].one; } } else { nd[root].one = nd[root].two = nd[root].more = nd[root].len; } } void change(int root, int x1, int x2, int c) { if (x1 <= nd[root].x1 && x2 >= nd[root].x2) { nd[root].c += c; if (nd[root].c == 2) { printf(""); } pushUP(root); return; } if (x1 < nd[ll].x2) change(ll, x1, x2, c); if (x2 > nd[rr].x1) change(rr, x1, x2, c); pushUP(root); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int t; scanf("%d", &t); for (int _ = 1; _ <= t; ++_) { printf("Case %d: ", _); int n, k = 0; scanf("%d", &n); for (int i = 0; i< n; ++i) { int x1, y1, z1, x2, y2, z2; scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2); mf[k] = mFace(y1, x1, x2, z1, z2, 1); xx[k] = x1; zz[k++] = z1; mf[k] = mFace(y2, x1, x2, z1, z2, -1); xx[k] = x2; zz[k++] = z2; } sort(mf, mf+k); sort(xx, xx+k); sort(zz, zz+k); int k1 = unique(xx, xx+k) - xx; int k2 = unique(zz, zz+k) - zz; build(0,k1-1,1); LL res = 0; int m; for (int i = 0; i < k2-1; ++i) { m = 0; for (int j = 0; j< k; ++j) { if (mf[j].z1 <= zz[i] && mf[j].z2 >= zz[i+1]) { tp[m++] = mf[j]; } } LL sum = 0; for (int j = 0; j< m; ++j) { if (j != 0) sum += (LL)nd[1].more * (LL)(tp[j].y - tp[j-1].y); change(1, tp[j].x1, tp[j].x2, tp[j].sz); } res += sum * (zz[i+1] - zz[i]); } printf("%I64d\n", res); } return 0; }
hdu 4419 Colourful Rectangle
如果搞懂了上一题,这题也差不多了,稍微加点变化#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> using namespace std; // http://acm.hdu.edu.cn/showproblem.php?pid=4419 const int MAXN = 25000; #define LL __int64 #define ll (root<<1) #define rr (ll|1) #define lson l,mm,ll #define rson mm,r,rr #define mid mm=(l+r)>>1 struct mFace { int y, x1, x2; int c, f; bool operator < (const mFace & a) const { return y < a.y; } void getIn(int yy, int xx1, int xx2, int cc, int ff) { y = yy; x1 = xx1; x2 = xx2; c = cc; f = ff; } }mf[MAXN]; const int MONE = 10*4; const int MC = 5*4; struct Node { int one[10]; int c[5], d; int x1, x2; int l, r; int len; void init() { memset(one, 0, MONE); memset(c, 0, MC); d = 0; len = x2-x1; } void cal() { d = 0; for (int i = 0; i< 3; ++i) { if (c[i]) d |= 1<<i; } } }nd[MAXN*3]; int xx[MAXN]; void build (int l, int r, int root) { nd[root].x1 = xx[l]; nd[root].x2 = xx[r]; nd[root].l = l, nd[root].r = r; nd[root].init(); if (l+1 == r) return; int mid; build(lson); build(rson); } void pushUP(int root) { int l = nd[root].l, r = nd[root].r; int d = nd[root].d; if (d == 0) { if (l+1 == r) { memset(nd[root].one, 0, MONE); } else { for (int i = 1; i<8; ++i) { nd[root].one[i] = nd[ll].one[i] + nd[rr].one[i]; } } } else { if (l+1 == r) { for (int i = 1; i< 8; ++i) { if ((i&d) == i) { nd[root].one[i] = nd[root].len; } else { nd[root].one[i] = 0; } } } else { for (int i = 1; i< 8; ++i) { if ((i&d) == i) { nd[root].one[i] = nd[root].len; } else { int a = i-(i&d); nd[root].one[i] = nd[ll].one[a] + nd[rr].one[a]; } } } } } void change(int root, int x1, int x2, int c, int ff) { if (x1 <= nd[root].x1 && x2 >= nd[root].x2) { nd[root].c[c] += ff; nd[root].cal(); pushUP(root); return; } if (x1 < nd[ll].x2) change(ll, x1, x2, c, ff); if (x2 > nd[rr].x1) change(rr, x1, x2, c, ff); pushUP(root); } char str[5]; int mot[10] = {1,2,4,3,5,6,7}; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int t; scanf("%d", &t); for (int _ = 1; _ <= t; ++_) { printf("Case %d:\n", _); int n, k = 0; scanf("%d", &n); for (int i = 0; i< n; ++i) { int x1, x2, y1, y2, c, f; scanf("%s%d%d%d%d", str, &x1, &y1, &x2, &y2); switch (str[0]) { case 'R': c = 0; break; case 'G': c = 1; break; case 'B': c = 2; break; } mf[k].getIn(y1,x1,x2,c,1); xx[k++] = x1; mf[k].getIn(y2,x1,x2,c,-1); xx[k++] = x2; } sort(mf, mf+k); sort(xx,xx+k); int k1 = unique(xx, xx+k) - xx; build(0,k1-1,1); LL res[10], nima; LL tp[10]; int ap[10]; memset(res, 0, sizeof res); for (int i = 0; i< k; ++i) { if (i != 0) { memcpy(ap, nd[1].one, MONE); tp[7] = ap[7]; tp[6] = ap[6]-ap[7]; tp[5]=ap[5]-ap[7]; tp[3]=ap[3]-ap[7]; LL cao = tp[7]+tp[6]+tp[5]+tp[3]; tp[4]=ap[4]-tp[5]-tp[6]-tp[7]; tp[2]=ap[2]-tp[3]-tp[6]-tp[7]; tp[1]=ap[1]-tp[3]-tp[5]-tp[7]; nima = (mf[i].y - mf[i-1].y); for (int j = 1; j< 8; ++j) res[j] += tp[j]*nima; } change(1, mf[i].x1, mf[i].x2, mf[i].c, mf[i].f); } for (int i = 0; i< 7; ++i) { printf("%I64d\n", res[mot[i]]); } } return 0; }
hdu 4288 Coder
算是线段树里一个比较巧妙的应用吧LL num[5]; 表示该段中偏移i个位置后,每隔5个数相加和
int cnt; 表示段中数的个数
结果显而易见就是 总段偏移2个位置后(从第三个数起)的结果#include <cstdio> #include <iostream> #include <cmath> #include <set> #include <algorithm> using namespace std; // http://acm.hdu.edu.cn/showproblem.php?pid=4288 const int MAXN = 100005; #define LL __int64 #define ll (root<<1) #define rr (ll|1) #define lson l,mm,ll #define rson mm+1,r,rr #define mid mm=(l+r)>>1 const int N = 5*sizeof(LL); struct Node { LL num[5]; int cnt; int x1, x2; void init() {memset(num, 0, N); cnt = 0;} }nd[MAXN*3]; int xx[MAXN], q[MAXN], s[MAXN]; void build (int l, int r, int root) { nd[root].x1 = xx[l]; nd[root].x2 = xx[r]; nd[root].init(); if (l == r) return; int mid; build(lson); build(rson); } void pushUP(int root) { int l = ll, r = rr, c1, c2; nd[root].cnt = (c1=nd[l].cnt) + nd[r].cnt; for (int i = 0; i< 5; ++i) { if (c1 < i) { nd[root].num[i] = nd[l].num[i] + nd[r].num[i-c1]; } else if (c1 == i) { nd[root].num[i] = nd[r].num[0]; } else { c2 = (c1-i)%5; if (c2 != 0) c2 = 5-c2; nd[root].num[i] = nd[l].num[i] + nd[r].num[c2]; } } } void change(int root, int x, int c) { if (nd[root].x2 == nd[root].x1) { if (c == 1) { nd[root].cnt = 1; nd[root].num[0] = x; } else { nd[root].init(); } return; } if (x <= nd[ll].x2) change(ll,x,c); else change(rr,x,c); pushUP(root); } char str[5]; set<int> mset; set<int>::iterator it; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int n; while (scanf("%d", &n) != EOF) { mset.clear(); for (int i = 0; i< n; ++i) { scanf("%s", str); if (strcmp(str, "add") == 0) { scanf("%d", s+i); q[i] = 1; mset.insert(s[i]); } else if (strcmp(str, "del") == 0) { scanf("%d", s+i); q[i] = -1; } else { q[i] = 3; } } int k = 0; for (it = mset.begin(); it != mset.end(); ++it) { xx[k++] = *it; } build(0,k-1,1); for (int i = 0; i< n; ++i) { if (q[i] != 3) change(1,s[i],q[i]); else printf("%I64d\n", nd[1].num[2]); } } return 0; }
hdu 4267 A Simple Problem with Integers
这算是比较灵活的线段树的应用一开始卡在如何解决延迟更新的问题上,借鉴了别人的思路,把求结果的那部分从低开始递归,这样就不需要延迟更新算是个教训吧#include <cstdio> #include <iostream> #include <cmath> #include <queue> #include <algorithm> #include <vector> // http://acm.hdu.edu.cn/showproblem.php?pid=4267 using namespace std; const int MAXN = 50005; const int NN = 11*sizeof(int); #define ll (root<<1) #define rr (ll | 1) #define lson l,m,ll #define rson m+1,r,rr #define mid m=(l+r)>>1 struct node { int l, r; int sz[11]; }data[MAXN*3]; int num[MAXN], mmp[MAXN]; void build(int l, int r, int root) { data[root].l = l; data[root].r = r; memset(data[root].sz, 0, NN); if (l == r) { mmp[l] = root; return; } int mid; build(lson); build(rson); } void change(int c, int k, int x, int y, int l, int r, int root) { if (x > y) return; if (x == l && y == r) { data[root].sz[k] += c; return; } int mid; if (y <= m) change(c,k,x,y,lson); else if (x > m) change(c,k,x,y,rson); else { change(c,k,x,m,lson); int a = (m-x)/k; change(c,k,x+(a+1)*k, y,rson); } } int getSum(int a, int root) { int l = data[root].l; int res = 0; for (int i = 1; i< 11; ++i) { if ((a-l)%i == 0) res += data[root].sz[i]; } if (root != 1) res += getSum(a,root>>1); return res; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int n; while (scanf("%d", &n) != EOF) { for (int i = 1; i<= n; ++i) scanf("%d", num+i); build(1,n,1); int m; scanf("%d", &m); while (m--) { int t,a,b,k,c; scanf("%d", &t); if (t == 1) { scanf("%d%d%d%d", &a, &b, &k, &c); change(c,k,a,b,1,n,1); } else { scanf("%d", &a); printf("%d\n", num[a]+getSum(a,mmp[a])); } } } return 0; }