线段树

来源:互联网 发布: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
原创粉丝点击