【codevs 1080】线段树练习 之 花样解法
2015-10-22 10:02
489 查看
线段树模板题
先上暴力
好了刚才的不算(虽然能AC)……
咳咳……
那么最开始的就是线段树咯~
恩恩,这就是线段树
然后第二个的话……显然就是好兄弟BIT了……
恩恩,这就是个BIT
然后,我最喜欢的,zkw线段树!
zkw太强大了……
然后……然后……也就是今天的重头戏
splay
恩恩,这就是棵splay……
作为后来的补充,来个分块
关于分块,调教了半小时后的经验是
编号从0开始
别忘了判断出界
任何时间要保证l < r
sqrt……
代码
总而言之就是这样了
一个模板题也没啥可说的……
先上暴力
[code]#include <iostream> #include <cstdio> #include <algorithm> #include <cstdio> using namespace std; const int MAXN = 100000 + 5; int num[MAXN]; int n,m,q,a,b; int main() { scanf("%d",&n); for(int i = 1;i <= n;i ++) scanf("%d",&num[i]); for(int i = 1;i <= n;i ++) num[i] += num[i - 1]; scanf("%d",&m); for(int i = 1;i <= m;i ++) { scanf("%d %d %d",&q,&a,&b); if(q == 1) for(int i = a;i <= n;i ++) num[i] += b; else printf("%d\n",num[b] - num[a - 1]); } return 0; }
好了刚才的不算(虽然能AC)……
咳咳……
那么最开始的就是线段树咯~
[code]#include<cstdio> #include<iostream> #define ll long long using namespace std; int num[200010]; struct dc{ int l,r; ll sum,add; }tree[200010*4]; void build(int p,int l,int r) { tree[p].l=l,tree[p].r=r; if(l==r) { tree[p].sum=num[l]; return ; } int mid=(l+r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); tree[p].sum=tree[p*2].sum+tree[p*2+1].sum; } void spread(int p) { if(tree[p].add) { tree[p*2].sum+=tree[p].add*(tree[p*2].r-tree[p*2].l+1); tree[p*2+1].sum+=tree[p].add*(tree[p*2+1].r-tree[p*2+1].l+1); tree[p*2].add+=tree[p].add; tree[p*2+1].add+=tree[p].add; tree[p].add=0; } } void change(int p,int a,int x) { if(a==tree[p].l&&tree[p].r==a) { tree[p].sum+=x; tree[p].add+=x; return; } spread(p); int mid=(tree[p].l+tree[p].r)/2; if(a<=mid) change(p*2,a,x); if(mid<a) change(p*2+1,a,x); tree[p].sum=tree[p*2].sum+tree[p*2+1].sum; } ll ask(int p,int l,int r) { if(l<=tree[p].l&&tree[p].r<=r) { return tree[p].sum; } spread(p); int mid=(tree[p].l+tree[p].r)/2; ll ans=0; if(l<=mid) ans+=ask(p*2,l,r); if(mid<r) ans+=ask(p*2+1,l,r); return ans; } int main() { int n;scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&num[i]); build(1,1,n); int S;scanf("%d",&S); while(S--) { int s;scanf("%d",&s); int a,b,x; if(s==1) { scanf("%d%d",&a,&x); change(1,a,x); } else { scanf("%d%d",&a,&b); printf("%lld\n",ask(1,a,b)); } } return 0; }
恩恩,这就是线段树
然后第二个的话……显然就是好兄弟BIT了……
[code]#include <iostream> #include <cstdio> using namespace std; const int MAXN = 100000 + 5; int n,z,a,b,tree[MAXN]; int lowbit(int x) { return x & (- x); } void add(int x,int y) { while(x <= n) { tree[x] += y; x += lowbit(x); } return; } int qzh(int x) { int ans = 0; while(x > 0) { ans += tree[x]; x -= lowbit(x); } return ans; } int answer(int s,int t) { return qzh(t) - qzh(s - 1); } int main() { scanf("%d",&n); for(int i = 1;i <= n;i ++) { scanf("%d",&z); add(i,z); } int m; scanf("%d",&m); for(int i = 1;i <= m;i ++) { scanf("%d",&z); if(z == 1) { scanf("%d %d",&a,&b); add(a,b); } else { scanf("%d %d",&a,&b); printf("%d\n",answer(a,b)); } } return 0; }
恩恩,这就是个BIT
然后,我最喜欢的,zkw线段树!
[code]#include <iostream> #include <cmath> #include <cstring> using namespace std; const int MAXN = 1000000 + 5; const int MAXM = 10000 + 5; int treee[MAXN],M; void init(int n) { M = 1 << ((int)log2(n + 1) + 1); for(int i = M + 1; i <= M + n; i++) cin >> treee[i]; for(int i = M - 1; i >= 1; i--) treee[i] = treee[i << 1] + treee[i << 1 | 1]; } void add(int x,int a) { for(treee[x += M] += a,x >>= 1;x;x >>= 1) { treee[x] = treee[x << 1] + treee[x << 1 | 1]; } return; } int answer(int s,int t) { int ans = 0; for(s = s + M - 1,t = t + M + 1;s ^ t ^ 1;s >>= 1,t >>= 1) { if(~s & 1) ans += treee[s ^ 1]; if(t & 1) ans += treee[t ^ 1]; } return ans; } int n,m,q,a,b; int main() { cin >> n; init(n); cin >> m; for(int i = 1;i <= m;i ++) { cin >> q >> a >> b; if(q == 1) { add(a,b); } if(q == 2) { cout << answer(a,b) << endl; } } return 0; }
zkw太强大了……
然后……然后……也就是今天的重头戏
splay
[code]#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN = 100000 + 5; struct tr { tr *ch[2],*f; int val,sz,cnt; bool dir() { return f -> ch[1] == this; } void maintain() { cnt = ch[0] -> cnt + ch[1] -> cnt + val; sz = ch[0] -> sz + ch[1] -> sz + 1; } void setc(tr *x,int v) { (ch[v] = x) -> f = this; } }tree[MAXN],*root,*null; int tot; tr* newdot(int v,tr *f) { tr *p = tree + tot++; p -> val = p -> cnt = v; p -> sz = 1; p -> ch[0] = p -> ch[1] = null; p -> f = f; return p; } void init() { tot = 0; null = newdot(0,null); null -> sz = 0; root = null; return; } void rot(tr *x) { tr *p = x -> f; int d = x -> dir(); p -> f -> setc(x,p -> dir()); p -> setc(x -> ch[d ^ 1],d); p -> maintain(); x -> setc(p,d ^ 1); if(root == p) root = x; return; } void splay(tr *x,tr *to = null) { while(x -> f != to) if(x -> f -> f == to) rot(x); else x -> dir() == x -> f -> dir() ? (rot(x -> f),rot(x)) : (rot(x),rot(x)); return; } void add(int p,int v) { tr *x = root; while(true) { x -> cnt += v; if(x -> ch[0] -> sz + 1 == p) { x -> val += v; break; } int d = x -> ch[0] -> sz + 1 <= p; if(d) p -= x -> ch[0] -> sz + 1; x = x -> ch[d]; } splay(x); return; } int sum(int xx,int yy) { int p = xx - 1; tr *x = root; while(true) { int d = x -> ch[0] -> sz + 1 <= p; if(x -> ch[0] -> sz + 1 == p) break; if(d) p -= x -> ch[0] -> sz + 1; x = x -> ch[d]; } splay(x); p = yy + 1; while(true) { int d = x -> ch[0] -> sz + 1 <= p; if(x -> ch[0] -> sz + 1 == p) break; if(d) p -= x -> ch[0] -> sz + 1; x = x -> ch[d]; } splay(x,root); return x -> ch[0] -> cnt; } int num[MAXN]; void build(int l,int r,tr * &x,tr *f) { if(l > r)return; int mid = (l + r) >> 1; x = newdot(num[mid],f); build(l,mid - 1,x -> ch[0],x); build(mid + 1,r,x -> ch[1],x); x -> maintain(); return; } int n,m,q,a,b; int main() { init(); scanf("%d",&n); for(int i = 2;i <= n + 1;i ++) scanf("%d",&num[i]); build(1,n + 2,root,null); scanf("%d",&m); for(int i = 1;i <= m;i ++) { scanf("%d %d %d",&q,&a,&b); if(q == 1) add(a + 1,b); else printf("%d\n",sum(a + 1,b + 1)); } return 0; }
恩恩,这就是棵splay……
作为后来的补充,来个分块
关于分块,调教了半小时后的经验是
编号从0开始
别忘了判断出界
任何时间要保证l < r
sqrt……
代码
[code]#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define KILL puts("haha") using namespace std; const int MAXN = 100000 + 5; int sum[MAXN],num[MAXN]; int n,m; int M; void init() { M = sqrt(n) + 1; for(int i = 0;i < n;i ++) if(i % M == 0) sum[i / M] = num[i]; else sum[i / M] += num[i]; return; } void change(int x,int y) { num[x] += y; sum[x / M] += y; return; } int sumer(int x,int y) { int ans = 0; while(x % M && x < y)//就是这里的这句 ans += num[x++]; while(y % M && y > x) ans += num[y--]; ans += num[y];//别忘了闭区间…… while(x < y) ans += sum[x / M],x += M; return ans; } int q,a,b; int main() { scanf("%d",&n); for(int i = 0;i < n;i ++) scanf("%d",&num[i]); init(); scanf("%d",&m); for(int i = 1;i <= m;i ++) { scanf("%d %d %d",&q,&a,&b); if(q == 1) change(a-1,b); else printf("%d\n",sumer(a-1,b-1)); } return 0; }
总而言之就是这样了
一个模板题也没啥可说的……
相关文章推荐
- HDU1041 Computer Transformation(java)
- 检查一个字符串是文本还是二进制
- 大型网站技术架构演化笔记
- Android四大组件应用系列——使用ContentProvider实现跨进程通讯
- .sln打开不了,显示the selected file is not a valid solution file
- zoj 3625 D - Geek's Collection(正项无穷级数,麦克劳林展开式,2015年10月AC)
- js中,加号扩展
- PHP 区分测试环境 生产环境的方法 环境变量
- mysql的数据类型int、bigint、smallint 和 tinyint取值范围
- 程序员和加班文化
- 13.4 目标检测的图像特征提取之(一)HOG特征
- kepler svn eclipse -
- matlab常用函数
- PowerDesigner反向生成PDM和name与注释互换
- java-java导入到Myeclipse出现原来的类引用出错
- volley JsonObjectRequest 提交参数
- 视图和表的区别
- Cyclomatic complexity
- 《人生》感悟
- Android客户端与PC服务端之间的SOCKET实现登陆功能(服务器)