AC题目简解-线段树
2014-02-28 13:54
183 查看
线段树:
http://www.notonlysuccess.com/index.php/segment-tree-complete/
鉴于notonlysuccess大牛的博客对于题目的思路写的很简陋,我就稍微补充下。
线段树的基本内容,是通过建二叉树来实现段的存储,最下面的叶子节点是每个值,左孩子和右孩子的父亲则是这个段的信息,依次推上去,实现从1..n的存储。可以通过程序带入样例来模拟这个过程体会。
建树:非叶子节点存储的都是段的值,而每个段,都有一个左边界和右边界。那么就建到叶子节点为止。每次都二分这个段,最后肯定会左边界等于右边界。
更新:如果是点更新则判断点即可,只是在判断该点在哪个区间的时候注意,一下。
查询:查询和更新类似
注意每一个return。
敌兵布阵:很简单的查询和单点更新
View Code
hdu1754 I Hate It :单点替换,注意pushup上去
View Code
hdu1394 Minimum Inversion Number 题意:求Inversion后的最小逆序数可以看看这篇博客
http://www.cnblogs.com/ziyi--caolu/archive/2013/01/15/2860768.html
View Code
http://www.notonlysuccess.com/index.php/segment-tree-complete/
鉴于notonlysuccess大牛的博客对于题目的思路写的很简陋,我就稍微补充下。
线段树的基本内容,是通过建二叉树来实现段的存储,最下面的叶子节点是每个值,左孩子和右孩子的父亲则是这个段的信息,依次推上去,实现从1..n的存储。可以通过程序带入样例来模拟这个过程体会。
建树:非叶子节点存储的都是段的值,而每个段,都有一个左边界和右边界。那么就建到叶子节点为止。每次都二分这个段,最后肯定会左边界等于右边界。
更新:如果是点更新则判断点即可,只是在判断该点在哪个区间的时候注意,一下。
查询:查询和更新类似
注意每一个return。
敌兵布阵:很简单的查询和单点更新
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=50010; int n; struct node{ int data,left,right; void init(int aleft,int aright){ left=aleft; right=aright; data=0; } }tree[MAXN<<2]; void pushup(int id){ tree[id].data=tree[id<<1].data+tree[id<<1|1].data; } void build(int left,int right,int id){ tree[id].init(left,right); if(left==right){ scanf("%d",&tree[id].data); return;//remember here! } int mid=(left+right)>>1; build(left,mid,id<<1); build(mid+1,right,id<<1|1); pushup(id); } int query(int left,int right,int id){ if(left==tree[id].left&&right==tree[id].right)return tree[id].data; int mid=(tree[id].left+tree[id].right)>>1; if(right<=mid)return query(left,right,id<<1); else if(left>mid)return query(left,right,id<<1|1); else return query(left,mid,id<<1)+query(mid+1,right,id<<1|1); } void update(int p,int vadd,int id){ if(tree[id].left==tree[id].right){ tree[id].data+=vadd; return ; } int mid=(tree[id].left+tree[id].right)>>1; if(p<=mid) update(p,vadd,id<<1); else update(p,vadd,id<<1|1); pushup(id); } int main(){ int t,a,b; scanf("%d",&t); char op[10]; for(int i=1;i<=t;i++){ printf("Case %d:\n",i); scanf("%d",&n); build(1,n,1); while(scanf("%s",op)&&op[0]!='E'){ scanf("%d%d",&a,&b); switch(op[0]){ case 'Q':printf("%d\n",query(a,b,1));break; case 'A':update(a,b,1);break; case 'S':update(a,-b,1);break; } } } return 0; }
View Code
hdu1754 I Hate It :单点替换,注意pushup上去
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=200010; struct node{ int data,left,right; void init(int aleft,int aright){ left=aleft;right=aright; data=0; } }; node tree[MAXN<<2]; inline void pushup(int id){ tree[id].data=max(tree[id<<1].data,tree[id<<1|1].data); } void build(int left,int right,int id){ tree[id].init(left,right);//this if(left==right){ scanf("%d",&tree[id].data); return; } int mid=(left+right)>>1; build(left,mid,id<<1); build(mid+1,right,id<<1|1); pushup(id); } void update(int p,int value,int id){ if(tree[id].left==tree[id].right){ tree[id].data=value; return; } int mid=(tree[id].left+tree[id].right)>>1; if(p<=mid)update(p,value,id<<1); else update(p,value,id<<1|1); pushup(id); } int query(int left,int right,int id){ if(left==tree[id].left&&right==tree[id].right)return tree[id].data; int mid=(tree[id].left+tree[id].right)>>1; if(right<=mid)return query(left,right,id<<1); else if(left>mid)return query(left,right,id<<1|1); else return max(query(left,mid,id<<1),query(mid+1,right,id<<1|1)); } int main(){ int n,m,a,b; char op[2]; while(scanf("%d%d",&n,&m)!=EOF){ build(1,n,1); for(int i=0;i<m;i++){ scanf("%s%d%d",&op,&a,&b); if(op[0]=='Q')printf("%d\n",query(a,b,1)); else update(a,b,1); } } return 0; }
View Code
hdu1394 Minimum Inversion Number 题意:求Inversion后的最小逆序数可以看看这篇博客
http://www.cnblogs.com/ziyi--caolu/archive/2013/01/15/2860768.html
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=5005; struct node{ int left,right,data; void init(int aleft,int aright){ left=aleft; right=aright; data=0;//the num of the value before it } }; node tree[MAXN<<2]; int n,a[MAXN]; inline void pushup(int id){ tree[id].data=tree[id<<1].data+tree[id<<1|1].data; } void build(int left,int right,int id){ tree[id].init(left,right); if(left==right)return; int mid=(left+right)>>1; build(left,mid,id<<1); build(mid+1,right,id<<1|1); } void update(int p,int id){ if(tree[id].left==tree[id].right){ tree[id].data=1; return; } int mid=(tree[id].left+tree[id].right)>>1; if(p<=mid)update(p,id<<1); else update(p,id<<1|1); pushup(id); } int query(int k,int id){ if(k>tree[id].right)return 0; if(k<=tree[id].left)return tree[id].data; int mid=(tree[id].left+tree[id].right)>>1; return query(k,id<<1)+query(k,id<<1|1); } int main(){ while(scanf("%d",&n)!=EOF){ build(0,n-1,1); int ans=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); ans+=query(a[i],1); update(a[i],1); } int minx=ans; for(int i=0;i<n;i++){ ans+=n-2*a[i]-1; if(ans<minx)minx=ans; } printf("%d\n",minx); } return 0; }
View Code
相关文章推荐
- AC题目简解-线段树
- AC题目简解-dp
- HDOJ 1166 敌兵布阵 第一次用线段树AC题目
- AC题目简解-数论
- AC题目简解-dp
- AC题目简解-数论
- 线段树题目
- AC日记——线段树练习三 codevs 1082 (分块尝试)
- POJ 题目2528 Mayor's posters(线段树+离散化)
- HDOJ 题目3564 Another LIS(线段树单点更新,LIS)
- ZOJ 题目1610 Count the Colors(线段树求颜色及有多少段)
- 一个有趣的题目【二分答案,2-SAT,线段树优化】
- HDOJ 题目2037今年暑假不AC(贪心)
- 终于把dp算法几个经典题目ac了
- 线段树题目分类+简单解释
- Codevs题目1191 数轴染色 (线段树)
- HDOJ 题目3397 Sequence operation(线段树区间覆盖异或合并)
- HDOJ 题目3911 Black And White(线段树区间异或区间合并)
- fzu 2105 线段树经典题目
- HDU ACM 11 2034 人见人恨的A-B(此题题目有问题,不要纠结代码为何可以AC)