SPOJ MULTQ3 线段树

来源:互联网 发布:java drawimage 厘米 编辑:程序博客网 时间:2024/05/20 04:29

题目链接:http://www.spoj.pl/problems/MULTQ3

http://vjudge.net/contest/view.action?cid=52045#problem/C

1.题意:

维护一段数列,操作一区间加一(update),操作二区间查询(query)模3为0的数的个数;

2.题解:

(1)首先要有线段树的基础;

(2)用三个标记v0,v1,v2分别记录:余0有几个数,余1有几个数,余2有几个数;

(3)用一个lazy标记记录当前区间被加了几次,lazy可取为0,1,2;

(4)每次update从根节点开始,第一步pushdown(把自己的lazy标记累加到儿子节点,并且根据自己的lazy标记的值更新儿子节点的v0,v1,v2,然后把自己的已经下传完毕的lazy标记取消),第二步递归调用update(把每个儿子节点的值也处理一遍使其成为正确的值,对于下传到刚好满足(ql<=l && r<=qr)的节点,直接把这个节点的v0,v1,v2的值修改正确,lazy标记也要加一,但是不下传了,原因是每次update我都保证每个被update访问过的节点是正确的值,所以现在这个刚好满足(ql<=l && r<=qr)的节点先前已经是正确的值了,所以我只要计算这一次操作过后的状态就行了,也就是直接把这个节点的v0,v1,v2的值修改正确,lazy标记也加一,但是不下传),第三步pushup(用(update递归更新)得到正确值的儿子节点去更新父亲节点,由于父亲节点的lazy标记已经给下传了,所以只有最下面的刚好满足(ql<=l && r<=qr)的节点此时才会有lazy标记);

(5)查询query(由于你不知道这个节点是之前刚好满足(ql<=l && r<=qr)的节点(打过lazy标记,但这个lazy标记也可能被后来的update操作中的pushdown或者query中的pushdown又传递给儿子了),还是已经被update操作中pushup更新成正确值的节点,你需要在query递归查询子区间之前,调用pushdown把当前节点的lazy标记传给子节点,并且把这次lazy标记对子节点单独造成的v0,v1,v2的变化描述出来,使得子节点是正确的值);

(6)初始化Build时一边构造一边pushup,使得当前节点的值是确定。


#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int MAXN=111111,MOD=3;int v[4*MAXN][3],lazy[4*MAXN];int ql,qr;int ans;void pushup(int o){    for(int i=0;i<3;i++)        v[o][i]=v[o<<1][i]+v[(o<<1)|1][i];}void pushdown(int o){    int ls=o<<1,rs=ls|1,tmp;    if(lazy[o]){        lazy[ls]=(lazy[ls]+lazy[o])%MOD;        lazy[rs]=(lazy[rs]+lazy[o])%MOD;        if(lazy[o]==1){            tmp=v[ls][0];            v[ls][0]=v[ls][2];            v[ls][2]=v[ls][1];            v[ls][1]=tmp;        }else if(lazy[o]==2){            tmp=v[ls][0];            v[ls][0]=v[ls][1];            v[ls][1]=v[ls][2];            v[ls][2]=tmp;        }        if(lazy[o]==1){            tmp=v[rs][0];            v[rs][0]=v[rs][2];            v[rs][2]=v[rs][1];            v[rs][1]=tmp;        }else if(lazy[o]==2){            tmp=v[rs][0];            v[rs][0]=v[rs][1];            v[rs][1]=v[rs][2];            v[rs][2]=tmp;        }        lazy[o]=0;    }}void Build(int o,int l,int r){    lazy[0]=0;    if(l==r){        v[o][0]=1;        v[o][1]=v[o][2]=0;        return;    }    int m=(l+r)>>1;    Build(o<<1,l,m);    Build((o<<1)|1,m+1,r);    pushup(o);}void update(int o,int l,int r){    if(ql<=l && r<=qr){        lazy[o]=(lazy[o]+1)%MOD;        int tmp=v[o][0];        v[o][0]=v[o][2];        v[o][2]=v[o][1];        v[o][1]=tmp;        return;    }    pushdown(o);    int M=(l+r)/2,ls=o<<1,rs=ls|1;    if(ql<=M) update(ls,l,M);    if(qr>M) update(rs,M+1,r);    pushup(o);}void Query(int o,int l,int r){    if(ql<=l && r<=qr){        ans+=v[o][0];        return;    }    pushdown(o);    int M=(l+r)>>1;    if(ql<=M) Query(o<<1,l,M);    if(qr>M) Query((o<<1)|1,M+1,r);}int main(){//    freopen("data.in","r",stdin);    int N,Q,op,a,b;    while(scanf("%d%d",&N,&Q)!=EOF){        Build(1,1,N);        while(Q--){            scanf("%d%d%d",&op,&a,&b);            ql=a+1,qr=b+1;            if(op==1){                ans=0;                Query(1,1,N);                printf("%d\n",ans);            }else                update(1,1,N);        }    }    return 0;}


0 0
原创粉丝点击