1、树状数组
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> using namespace std; #define INF ~0U>>1 const int MAX=300; int n,num[MAX],c[MAX],X,Y; int lowbit(int x){ return x&(-x);} int SUM(int l,int r){//区间查询 int sum=0; for(int i=r;i;i-=lowbit(i)) sum+=c[i]; for(int i=l-1;i;i-=lowbit(i)) sum-=c[i]; return sum; } void change(int x,int m){ for(int i=x;i<=n;i+=lowbit(i)) c[i]+=m;}//单点修改 int main(){ memset(c,0,sizeof(c)); cin >> n; for(int i=1;i<=n;i++){ cin >> num[i]; for(int j=i-lowbit(i)+1;j<=i;j++) c[i]+=num[j]; } cout << "1 X Y:sum[Y]-sum[X](X<Y)" << endl << "2 X Y:num[X]=Y" << endl << "0:end" << endl; int i; do{ cin >> i >> X >> Y; if(!i) break; if(i==1) cout << SUM(X,Y) << endl; if(i==2) change(X,Y),cout << "FINISH!" << endl; }while(i); return 0; }
(求逆序对)
/************************** 2015-08-09 20:22:51 DataStructure -> 树 -> 树状数组 利用树状数组求逆序对 Poj 2233 **************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; int c[500003]; //辅助数组,Ci = A(i-lowbit(i)+1) + A(i-lowbit(i)+2) + ……+ Ai int a[500003]; //离散化后的数据序列 const int maxn = 500003; struct Node //value记录具体数值, pos代表读入顺序 { int value,pos; bool operator<(const Node a)const{ return value<a.value; } }s[500003]; //读入时的数据序列 int lowbit(int x) //求x的二进制表达式中最右边的1所对应的值 { return x&(-x); } void insert(int pos,int x) //让A(pos)增加x { while(pos<=maxn) { c[pos]+=x; pos+=lowbit(pos); } } int sum(int x) //求A1 + A2 + ……+ Ax 的前缀和 { int s=0; while(x>0) { s+=c[x]; x-=lowbit(x); } return s; } int main() { while(scanf("%d",&n)==1&&n) { memset(c,0,sizeof(c)); memset(a,0,sizeof(a)); for(int i=0;i<n;i++) { scanf("%d",&s[i].value); s[i].pos=i+1; } sort(s,s+n); int id=1; a[s[0].pos]=1; for(int i=1;i<n;i++)//离散化 { if(s[i].value!=s[i-1].value) { a[s[i].pos]=++id; } else { a[s[i].pos]=id; } } long long int ans=0; for(int i=1;i<=n;i++)//一个个插入求逆序对 { insert(a[i],1); ans+=(i-sum(a[i])); cout<<i<<" "<<sum(a[i])<<endl; } printf("%lld ",ans); } return 0; }
2、线段树
①单点
#include<iostream> #include<algorithm> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 10000 #define inf 987654321 int n,rt,Max[maxn<<2],Min[maxn<<2],Sum[maxn<<2],a[maxn<<2]; using namespace std; void pushup(int rt){ Max[rt] = max(Max[rt<<1],Max[rt<<1|1]); Min[rt] = min(Min[rt<<1],Min[rt<<1|1]); Sum[rt] = Sum[rt<<1]+Sum[rt<<1|1]; } void buildtree(int l,int r,int rt){ if(l == r){ Max[rt] = Min[rt] = Sum[rt] = a[l]; return; } int m = (l+r)>>1; buildtree(lson); buildtree(rson); pushup(rt); } void setval(int p,int v,int l,int r,int rt){ if(l == r){ Max[rt] = Min[rt] = Sum[rt] = v; return; } int m = (l+r)>>1; if(p <= m) update(p,v,lson); else update(p,v,rson); pushup(rt); } void addval(int p,int v,int l,int r,int rt){ if(l == r){ Max[rt] += v; Min[rt] += v; Sum[rt] += v; return; } int m = (l+r)>>1; if(p <= m) update(p,v,lson); else update(p,v,rson); pushup(rt); } int query_max(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return Max[rt]; int m = (l+r)>>1; int ret = -inf; if(L <= m) ret = max(ret,query(L,R,lson)); if(R > m) ret = max(ret,query(L,R,rson)); return ret; } int query_min(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return Min[rt]; int m = (l+r)>>1; int ret = inf; if(L <= m) ret = min(ret,query(L,R,lson)); if(R > m) ret = min(ret,query(L,R,rson)); return ret; } int query_sum(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return Sum[rt]; int m = (l+r)>>1; int ret = 0; if(L <= m) ret += query(L,R,lson); if(R > m) ret += query(L,R,rson); return ret; } int main(){ cin>>n; buildtree(1,n,1); return 0; }
②区间修改
// Fast Sequence Operations I // Rujia Liu // 输入格式: // n m 数组范围是a[1]~a[n],初始化为0。操作有m个 // 1 L R v 表示设a[L]+=v, a[L+1]+v, ..., a[R]+=v // 2 L R 查询a[L]~a[R]的sum, min和max #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxnode = 1<<17; int _sum, _min, _max, op, qL, qR, v; struct IntervalTree { int sumv[maxnode], minv[maxnode], maxv[maxnode], addv[maxnode]; // 维护信息 void maintain(int o, int L, int R) { int lc = o*2, rc = o*2+1; sumv[o] = minv[o] = maxv[o] = 0; if(R > L) { sumv[o] = sumv[lc] + sumv[rc]; minv[o] = min(minv[lc], minv[rc]); maxv[o] = max(maxv[lc], maxv[rc]); } if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1); } } void update(int o, int L, int R) { int lc = o*2, rc = o*2+1; if(qL <= L && qR >= R) { // 递归边界 addv[o] += v; // 累加边界的add值 } else { int M = L + (R-L)/2; if(qL <= M) update(lc, L, M); if(qR > M) update(rc, M+1, R); } maintain(o, L, R); // 递归结束前重新计算本结点的附加信息 } void query(int o, int L, int R, int add) { if(qL <= L && qR >= R) { // 递归边界:用边界区间的附加信息更新答案 _sum += sumv[o] + add * (R-L+1); _min = min(_min, minv[o] + add); _max = max(_max, maxv[o] + add); } else { // 递归统计,累加参数add int M = L + (R-L)/2; if(qL <= M) query(o*2, L, M, add + addv[o]); if(qR > M) query(o*2+1, M+1, R, add + addv[o]); } } }; const int INF = 1000000000; IntervalTree tree; int main() { int n, m; while(scanf("%d%d", &n, &m) == 2) { memset(&tree, 0, sizeof(tree)); while(m--) { scanf("%d%d%d", &op, &qL, &qR); if(op == 1) { scanf("%d", &v); tree.update(1, 1, n); } else { _sum = 0; _min = INF; _max = -INF; tree.query(1, 1, n, 0); printf("%d %d %d ", _sum, _min, _max); } } } return 0; }
③区间替换
// Fast Sequence Operations II // Rujia Liu // 输入格式: // n m 数组范围是a[1]~a[n],初始化为0。操作有m个 // 1 L R v 表示设a[L]=a[L+1]=...=a[R] = v。其中v > 0 // 2 L R 查询a[L]~a[R]的sum, min和max #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxnode = 1<<17; int _sum, _min, _max, op, qL, qR, v; struct IntervalTree { int sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode]; // 维护信息 void maintain(int o, int L, int R) { int lc = o*2, rc = o*2+1; if(R > L) { sumv[o] = sumv[lc] + sumv[rc]; minv[o] = min(minv[lc], minv[rc]); maxv[o] = max(maxv[lc], maxv[rc]); } if(setv[o] >= 0) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (R-L+1); } } // 标记传递 void pushdown(int o) { int lc = o*2, rc = o*2+1; if(setv[o] >= 0) { //本结点有标记才传递。注意本题中set值非负,所以-1代表没有标记 setv[lc] = setv[rc] = setv[o]; setv[o] = -1; // 清除本结点标记 } } void update(int o, int L, int R) { int lc = o*2, rc = o*2+1; if(qL <= L && qR >= R) { // 标记修改 setv[o] = v; } else { pushdown(o); int M = L + (R-L)/2; if(qL <= M) update(lc, L, M); else maintain(lc, L, M); if(qR > M) update(rc, M+1, R); else maintain(rc, M+1, R); } maintain(o, L, R); } void query(int o, int L, int R) { if(setv[o] >= 0) { // 递归边界1:有set标记 _sum += setv[o] * (min(R,qR)-max(L,qL)+1); _min = min(_min, setv[o]); _max = max(_max, setv[o]); } else if(qL <= L && qR >= R) { // 递归边界2:边界区间 _sum += sumv[o]; // 此边界区间没有被任何set操作影响 _min = min(_min, minv[o]); _max = max(_max, maxv[o]); } else { // 递归统计 int M = L + (R-L)/2; if(qL <= M) query(o*2, L, M); if(qR > M) query(o*2+1, M+1, R); } } }; const int INF = 1000000000; IntervalTree tree; int main() { int n, m; while(scanf("%d%d", &n, &m) == 2) { memset(&tree, 0, sizeof(tree)); memset(tree.setv, -1, sizeof(tree.setv)); tree.setv[1] = 0; while(m--) { scanf("%d%d%d", &op, &qL, &qR); if(op == 1) { scanf("%d", &v); tree.update(1, 1, n); } else { _sum = 0; _min = INF; _max = -INF; tree.query(1, 1, n); printf("%d %d %d ", _sum, _min, _max); } } } return 0; }
3、Spare Table(静态RMQ)
void init_rmq(){ for(int i = 0;i < n;i++) d[i][0] = money[i]; for(int j = 1;(1<<j) <= n;j++){ for(int i = 0;i + (1<<j) - 1 < n;i++){ d[i][j] = min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } } } int rmq(int l,int r){ int k = 0; while((1<<(k+1)) <= r-l+1) k++; return min(d[l][k],d[r-(1<<k)+1][k]); }
4.动态RMQ
// Dynamic RMQ // Rujia Liu // 输入格式: // n m 数组范围是a[1]~a[n],初始化为0。操作有m个 // 1 p v 表示设a[p]=v // 2 L R 查询a[L]~a[R]的min #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int INF = 1000000000; const int maxnode = 1<<17; int op, qL, qR, p, v; struct IntervalTree { int minv[maxnode]; void update(int o, int L, int R) { int M = L + (R-L)/2; if(L == R) minv[o] = v; // 叶结点,直接更新minv else { // 先递归更新左子树或右子树 if(p <= M) update(o*2, L, M); else update(o*2+1, M+1, R); // 然后计算本结点的minv minv[o] = min(minv[o*2], minv[o*2+1]); } } int query(int o, int L, int R) { int M = L + (R-L)/2, ans = INF; if(qL <= L && R <= qR) return minv[o]; // 当前结点完全包含在查询区间内 if(qL <= M) ans = min(ans, query(o*2, L, M)); // 往左走 if(M < qR) ans = min(ans, query(o*2+1, M+1, R)); // 往右走 return ans; } }; IntervalTree tree; int main() { int n, m; while(scanf("%d%d", &n, &m) == 2) { memset(&tree, 0, sizeof(tree)); while(m--) { scanf("%d", &op); if(op == 1) { scanf("%d%d", &p, &v); tree.update(1, 1, n); } else { scanf("%d%d", &qL, &qR); printf("%d ", tree.query(1, 1, n)); } } } return 0; }
5.名次树
/*支持以下操作 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前驱(前驱定义为小于x,且最大的数) 6. 求x的后继(后继定义为大于x,且最小的数) */ #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; struct data{ int l,r,v,size,rnd,w; }tr[100005]; int n,size,root,ans; void update(int k)//更新结点信息 { tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w; } void rturn(int &k) { int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k; tr[t].size=tr[k].size;update(k);k=t; } void lturn(int &k) { int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k; tr[t].size=tr[k].size;update(k);k=t; } void insert(int &k,int x) { if(k==0) { size++;k=size; tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand(); return; } tr[k].size++; if(tr[k].v==x)tr[k].w++; else if(x>tr[k].v) { insert(tr[k].r,x); if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k); } else { insert(tr[k].l,x); if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k); } } void del(int &k,int x) { if(k==0)return; if(tr[k].v==x) { if(tr[k].w>1) { tr[k].w--;tr[k].size--;return; } if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r; else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd) rturn(k),del(k,x); else lturn(k),del(k,x); } else if(x>tr[k].v) tr[k].size--,del(tr[k].r,x); else tr[k].size--,del(tr[k].l,x); } int query_rank(int k,int x) { if(k==0)return 0; if(tr[k].v==x)return tr[tr[k].l].size+1; else if(x>tr[k].v) return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x); else return query_rank(tr[k].l,x); } int query_num(int k,int x) { if(k==0)return 0; if(x<=tr[tr[k].l].size) return query_num(tr[k].l,x); else if(x>tr[tr[k].l].size+tr[k].w) return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w); else return tr[k].v; } void query_pro(int k,int x) { if(k==0)return; if(tr[k].v<x) { ans=k;query_pro(tr[k].r,x); } else query_pro(tr[k].l,x); } void query_sub(int k,int x) { if(k==0)return; if(tr[k].v>x) { ans=k;query_sub(tr[k].l,x); } else query_sub(tr[k].r,x); } int main() { scanf("%d",&n); int opt,x; for(int i=1;i<=n;i++) { scanf("%d%d",&opt,&x); switch(opt) { case 1:insert(root,x);break; case 2:del(root,x);break; case 3:printf("%d ",query_rank(root,x));break; case 4:printf("%d ",query_num(root,x));break; case 5:ans=0;query_pro(root,x);printf("%d ",tr[ans].v);break; case 6:ans=0;query_sub(root,x);printf("%d ",tr[ans].v);break; } } return 0; }