线段树
来源:互联网 发布:js点击小图切换大图 编辑:程序博客网 时间:2024/06/11 00:01
这个专辑直接戳这位牛的博客吧http://www.notonlysuccess.com/index.php/segment-tree-complete/
补充一道题目吧:
HDU3397,
题意:0 a b:区间置0 1 a b :区间置1 2 a b:区间取反 3 a b:区间查询1个数 4 a b:区间查询最长连续1长度
此题相当于有两个lazy标记,是一道比较好的题目。
#include "cstdio"#include "cstring"#include<algorithm>#include<cmath>#define lson id<<1#define rson id<<1|1using namespace std;const int maxn=(int)1e5+5;struct node { int left,right; int reset;//置0置1标记 bool reversal;//取反标记 int lone,rone,mone,lzero,rzero,mzero;//连续1,0的长度 int sum;//1的个数} tree[maxn<<2];void pushup(int id){ if(tree[id].left==tree[id].right)return ; int len=tree[id].right-tree[id].left+1; tree[id].lone=tree[lson].lone;tree[id].rone=tree[rson].rone; if(tree[id].lone==(len+1)>>1)tree[id].lone+=tree[rson].lone;//如果左区间全都是1 if(tree[id].rone==len>>1)tree[id].rone+=tree[lson].rone;//如果右区间全都是1 tree[id].mone=max(max(tree[lson].mone,tree[rson].mone),tree[lson].rone+tree[rson].lone);//两个区间中间的部分可能接起来 tree[id].lzero=tree[lson].lzero;tree[id].rzero=tree[rson].rzero; if(tree[id].lzero==(len+1)>>1)tree[id].lzero+=tree[rson].lzero; if(tree[id].rzero==len>>1)tree[id].rzero+=tree[lson].rzero; tree[id].mzero=max(max(tree[lson].mzero,tree[rson].mzero),tree[lson].rzero+tree[rson].lzero); tree[id].sum=tree[lson].sum+tree[rson].sum;}void build(int left,int right,int id) { tree[id].left=left; tree[id].right=right;tree[id].reset=-1; tree[id].reversal=false; if(left==right) { scanf("%d",&tree[id].sum); tree[id].lone=tree[id].rone=tree[id].mone=(tree[id].sum==1); tree[id].lzero=tree[id].rzero=tree[id].mzero=(tree[id].sum==0); return ; } int mid=(left+right)>>1; build(left,mid,lson); build(mid+1,right,rson); pushup(id);}void XOR(int id) { swap(tree[id].lone,tree[id].lzero); swap(tree[id].rone,tree[id].rzero); swap(tree[id].mone,tree[id].mzero); tree[id].sum=tree[id].right-tree[id].left+1-tree[id].sum;}void reset(int id){ int z=(tree[id].reset==0)?tree[id].right-tree[id].left+1:0; int y=(tree[id].reset==1)?tree[id].right-tree[id].left+1:0; tree[id].lzero=tree[id].rzero=tree[id].mzero=z; tree[id].lone=tree[id].rone=tree[id].mone=y; tree[id].sum=y;}/*PushDown的真谛:是将当前id的状态push下去,并且将左右儿子的状态都算出来,而id自己的状态实际上已经在update的时候算出来了*/void pushdown(int id) { if(tree[id].left==tree[id].right)return ; if(tree[id].reset!=-1) { tree[lson].reset=tree[rson].reset=tree[id].reset; tree[lson].reversal=tree[rson].reversal=0;//取反标记置0,因为它的状态已经算出来了,所以直接把儿子取反的置0即可 reset(lson);reset(rson); tree[id].reset=-1; } if(tree[id].reversal) { XOR(lson);XOR(rson); tree[lson].reversal^=1; tree[rson].reversal^=1; tree[id].reversal=0; }}void update(int left,int right,int id,int op) { pushdown(id);//先pushdown下去。 if(left<=tree[id].left&&right>=tree[id].right) {//id的状态在这里更新,但是id的标记更新,在pushdown的时候才取消 if(op<2) { tree[id].reset=op; reset(id); } else { tree[id].reversal=1; XOR(id); } return ; } int mid=(tree[id].left+tree[id].right)>>1; if(right<=mid)update(left,right,lson,op); else if(left>mid)update(left,right,rson,op); else { update(left,mid,lson,op); update(mid+1,right,rson,op); } pushup(id);}int query(int left,int right,int id,int op) { pushdown(id);//先pushdown下去 if(left<=tree[id].left&&right>=tree[id].right) { if(op)return tree[id].sum; else return tree[id].mone;//由于mone的更新方式,这里只要return monoe就行 } int mid=(tree[id].left+tree[id].right)>>1; if(right<=mid)return query(left,right,lson,op); else if(left>mid)return query(left,right,rson,op); else { if(op)return query(left,mid,lson,op)+query(mid+1,right,rson,op); else {//这里是一个小重点,因为前面已经pushdown下去了,所以左右儿子的状态已经更新了,注意左右儿子中间部分可能会结合起来。 int ret=min(tree[lson].rone,tree[lson].right-left+1)+ min(tree[rson].lone,right-tree[rson].left+1); int ans=max(query(left,mid,lson,op),query(mid+1,right,rson,op)); return max(ans,ret); } }}int n,m;int main(int argc, char const *argv[]) { int t; int op,x,y; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); build(1,n,1); while(m--) { scanf("%d%d%d",&op,&x,&y); x++;y++; if(op<3)update(x,y,1,op); else printf("%d\n",query(x,y,1,op%2)); } } return 0;}
0 0
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- POJ1470Closest Common Ancestors 最近公共祖先LCA 的 离线算法 Tarjan
- POJ1330Nearest Common Ancestors最近公共祖先LCA问题
- mysql
- 数据结构实验:图的操作
- POJ1986 DistanceQueries 最近公共祖先LCA 离线算法Tarjan
- 线段树
- AC题目简解-线段树
- 在C#中调用windows API函数 最大、最小化窗口
- 数论之因子个数的求法
- Cocos2d-X的动画的打击感支持。
- ASSIC码对照表
- 筛法求素数及其优化
- event.keycode大全(javascript)
- 广告终结者的自定义规则