[NOIP模拟][线段树+标记下传]Query

来源:互联网 发布:怎么给手机网络加速 编辑:程序博客网 时间:2024/06/04 19:16

题目描述:
万恶的大头又出现了!他正在玩一个智障游戏:打怪兽。
现在大头的屏幕上出现了一排怪兽,每只怪兽头上有一个血条,每次大头可以选择一个区间进行攻击,攻击值为 K ,这个区间中血量小于 K 的怪兽都会被大头无情地干掉,当然怪兽不会坐以待毙,对于一个区间的怪兽,他们会在某个时刻血量同时加 X 。
大头头虽然很大,但是 IQ 并不高,在座的各位选手都不知道比他高到哪里去了。这个时候大头使出了大招——作弊器,然而大头的作弊器并不高级只能将选择的区间内血量为 7 的倍数的怪兽干掉,问:他能干掉多少怪兽?
输入格式:
第一行一个正整数 n ;
接下来 n 行 n 个整数;
再接下来一个正整数 Q ,表示操作的个数;
接下来 Q 行每行若干个整数。如果第一个数是 add ,后接 3 个正整数 a,b,X,表示在区间 [a,b] 内每个数增加 X,如果是 count,表示统计区间 [a,b] 能被 7 整除的个数。
输出格式:
对于每个询问输出一行一个答案。
样例输入:
3
2 3 4
6
count 1 3
count 1 2
add 1 3 2
count 1 3
add 1 3 3
count 1 3
样例输出:
0
0
0
1
题目分析:
线段树。懒标记+标记下传。稍微特殊的就是对于线段树tree结构体,开一个tot数组,用来存模7后不同余数的个数,修改也是修改余数值,详见代码。
附代码:

#include<iostream>#include<cstring>#include<string>#include<cstdlib>#include<cstdio>#include<ctime>#include<queue>#include<iomanip>#include<cmath>#include<cctype>#include<set>#include<map>#include<algorithm>using namespace std;const int maxn=1e5+10;int n,q,a[maxn],x,y,z;char s[10];struct node{    int tot[10];//下标代表模7的余数,存的是个数     int w;    int add;}tree[4*maxn];int readint(){    char ch;int f=1,i=0;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-')    {        ch=getchar();        f=-1;    }    for(;ch>='0'&&ch<='9';ch=getchar())        i=(i<<3)+(i<<1)+ch-'0';    return i*f;}void create(int l,int r,int k){    if(l==r)    {        tree[k].w=a[l]%7;        tree[k].tot[a[l]%7]=1;        return;    }    int mid=(l+r)>>1;    create(l,mid,k<<1);    create(mid+1,r,k<<1|1);    for(int i=0;i<=6;i++)        tree[k].tot[i]=tree[k<<1].tot[i]+tree[k<<1|1].tot[i];}void change(int k,int v)//本题的关键操作,一个区间先已知各种余数分别的个数,修改的就是余数,而不是个数 {                       //如原先tot[0]=4,tot[1]=5,tot[5]=3,区间加2,则tot[2]=4,tot[3]=5,tot[0]=3    int tot[10];            for(int i=0;i<=6;i++)        tot[i]=tree[k].tot[i];    for(int i=0;i<=6;i++)        tree[k].tot[(i+v)%7]=tot[i];}void push_down(int k){    if(tree[k].add==0) return;    tree[k<<1].add=(tree[k<<1].add+tree[k].add)%7;change(k<<1,tree[k].add);    tree[k<<1|1].add=(tree[k<<1|1].add+tree[k].add)%7;change(k<<1|1,tree[k].add);    tree[k].add=0;}void update(int l,int r,int k,int x,int y,int w)//修改操作,修改的是add值,即标记 {    if(x<=l&&y>=r)    {        tree[k].add=(tree[k].add+w)%7;        change(k,w);        return;    }    int mid=(l+r)>>1;    push_down(k);    if(x<=mid) update(l,mid,k<<1,x,y,w);    if(y>mid) update(mid+1,r,k<<1|1,x,y,w);    for(int i=0;i<=6;i++)        tree[k].tot[i]=tree[k<<1].tot[i]+tree[k<<1|1].tot[i];}int query(int l,int r,int k,int x,int y){    int ans=0,ans1=0,ans2=0;    if(x<=l&&y>=r)        return tree[k].tot[0];    int mid=(l+r)>>1;    push_down(k);    if(x<=mid) ans1=query(l,mid,k<<1,x,y);    if(y>mid) ans2=query(mid+1,r,k<<1|1,x,y);    return ans=ans1+ans2;}int main(){    //freopen("seg.in","r",stdin);    //freopen("seg.out","w",stdout);    n=readint();    for(int i=1;i<=n;i++)        a[i]=readint();    create(1,n,1);    q=readint();    while(q--)    {        scanf("%s",s);        if(s[0]=='c')        {            x=readint();y=readint();            int ans=query(1,n,1,x,y);            cout<<ans<<endl;        }        else        {            x=readint();y=readint();z=readint();            z=z%7;            update(1,n,1,x,y,z);        }    }    return 0;}
原创粉丝点击