HDU3397(Sequence operation)线段树的多种操作

来源:互联网 发布:交换机 限制端口带宽 编辑:程序博客网 时间:2024/05/12 02:40
/**********************************************题目大意:0 a b将区间[a,b]所有数全部变成01 a b将区间[a,b]所有数全部变成12 a b将区间[a,b]中所有数0 1互换,0变1,1变03 a b输出区间[a,b]中1的个数4 a b输出区间[a,b]中最长连续1的个数算法分析:涉及到线段树的多种操作;0,1两种操作可以合并到一起写;0,1互换即线段树的异或操作;查询区间最长连续1个数的过程中;maxl=[l,m]上最长连续1个数;maxl=[m+1,r]上最长连续1的个数;maxm=min(m-l+1,左孩子的rs)+min(r-m,右孩子的ls);结果应该是这三个中的最大值,即max(maxl,maxr,maxm);其中查询操作和pku3667类似;***********************************************/#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<climits>#include<algorithm>using namespace std;#define L l,m,u<<1#define R m+1,r,u<<1|1const int N =100010;struct node{    int l,r;    int ls,ms,rs;//ms存储最长连续1的数量    int flag;//01状态    int total;//区间1的总数} t[N*3];int len(int u){    return t[u].r-t[u].l+1;}int mid(int u){    return (t[u].l+t[u].r)>>1;}void sets(int u,int x){    t[u].ls=t[u].ms=t[u].rs=t[u].total=x*(t[u].r-t[u].l+1);    t[u].flag=x;}void build(int l,int r,int u){    t[u].l=l;    t[u].r=r;    t[u].ls=t[u].rs=t[u].ms=t[u].total=t[u].flag=0;    if(l==r)        return;    int m=mid(u);    build(L);    build(R);}void PushUp(int u)//把当前结点的信息更新到父结点{    t[u].flag=(t[u<<1].flag==t[u<<1|1].flag?t[u<<1].flag:-1);//更新状态    t[u].ls=t[u<<1].ls+((t[u<<1].ls==len(u<<1))?t[u<<1|1].ls:0);//更新左    t[u].rs=t[u<<1|1].rs+((t[u<<1|1].rs==len(u<<1|1))?t[u<<1].rs:0);//更新右    t[u].ms=max(t[u<<1].rs+t[u<<1|1].ls,max(t[u<<1].ms,t[u<<1|1].ms));//更新整体    t[u].total=t[u<<1].total+t[u<<1|1].total;//更新1的总数}void update(int l,int r,int u,int x)//更新区间[l,r]0、1状态{    if(t[u].flag==x)        return;    if(t[u].l==l&&t[u].r==r)    {        sets(u,x);        return;    }    if(t[u].flag>=0)    {        sets(u<<1,t[u].flag);        sets(u<<1|1,t[u].flag);        t[u].flag=-1;    }    int m=mid(u);    if(r<=m)    {        update(l,r,u<<1,x);    }    else if(l>m)    {        update(l,r,u<<1|1,x);    }    else    {        update(L,x);        update(R,x);    }    PushUp(u);}void swap(int l,int r,int u)//[l,r]0、1交换{    if(t[u].l>=l&&t[u].r<=r&&(t[u].flag==0||t[u].flag==1))    {        int x=t[u].flag^1;        sets(u,x);        return;    }    if(t[u].flag>=0)    {        sets(u<<1,t[u].flag);        sets(u<<1|1,t[u].flag);    }    int m=mid(u);    if(r<=m)    {        swap(l,r,u<<1);    }    else if(l>m)    {        swap(l,r,u<<1|1);    }    else    {        swap(L);        swap(R);    }    PushUp(u);}int find1(int l,int r,int u)//找区间[l,r]内的1的个数{    if(t[u].l==l&&t[u].r==r)    {        return t[u].total;    }    if(t[u].flag>=0)    {        sets(u<<1,t[u].flag);        sets(u<<1|1,t[u].flag);    }    int m=mid(u);    if(r<=m)    {        return find1(l,r,u<<1);    }    else if(l>m)    {        return find1(l,r,u<<1|1);    }    else    {        return find1(L)+find1(R);    }}int find2(int l,int r,int u)//找区间[l,r]内最长连续1的个数{    if(t[u].l==l&&t[u].r==r)    {        return t[u].ms;    }    if(t[u].flag>=0)    {        sets(u<<1,t[u].flag);        sets(u<<1|1,t[u].flag);    }    int m=mid(u);    if(r<=m)    {        return find2(l,r,u<<1);    }    else if(l>m)    {        return find2(l,r,u<<1|1);    }    else    {        int maxl=find2(L);        int maxr=find2(R);        int maxm=min(m-l+1,t[u<<1].rs)+min(r-m,t[u<<1|1].ls);        return max(maxm,max(maxl,maxr));    }}int main(){    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        scanf("%d%d",&n,&m);        build(0,n-1,1);        for(int i=0; i<n; i++)        {            int x;            scanf("%d",&x);            if(x!=0)                update(i,i,1,x);        }        for(int i=0; i<m; i++)        {            int op,a,b;            scanf("%d%d%d",&op,&a,&b);            if(op==0||op==1)                update(a,b,1,op);            else if(op==2)                swap(a,b,1);            else if(op==3)                printf("%d\n",find1(a,b,1));            else if(op==4)                printf("%d\n",find2(a,b,1));        }    }    return 0;}

原创粉丝点击