codevs1082 线段树练习3

来源:互联网 发布:pc1500 水利计算软件 编辑:程序博客网 时间:2024/04/30 10:17

线段树

蒟蒻年轻的时候照着hzwer神犇的写的,勿喷= =

#include<cstdio>#include<bits/stdc++.h>#include<cstring>#include<cstdlib>#include<algorithm>#define R0(i,n) for(int i=0;i<n;++i)#define R1(i,n) for(int i=1;i<=n;++i)#define CLR(x,c) memset(x,c,sizeof x)using namespace std;typedef long long ll;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}struct data{int l,r;ll sum;int tag;}tr[800001];int aa[200001],n,q;void build(int k,int a,int b){    tr[k].l=a,tr[k].r=b;    if(a==b){        tr[k].sum=aa[a];        return ;    }    int mid=(a+b)>>1;    build(k<<1,a,mid);    build(k<<1|1,mid+1,b);    tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;} void pd(int k){    int x=tr[k].r-tr[k].l+1;    tr[k<<1].tag+=tr[k].tag,tr[k<<1|1].tag+=tr[k].tag;    tr[k<<1].sum+=(x- (x>>1) )*tr[k].tag;    tr[k<<1|1].sum+=(x>>1)*tr[k].tag;    tr[k].tag=0;} void update(int k,int a,int b,int x){    int l=tr[k].l,r=tr[k].r;    if(l==a&&r==b){        tr[k].tag+=x;        tr[k].sum+=(b-a+1)*x;        return;    }    if(tr[k].tag)pd(k);    int mid=(l+r)>>1;    if(b<=mid)update(k<<1,a,b,x);    else if(a>mid)update(k<<1|1,a,b,x);    else update(k<<1,a,mid,x),update(k<<1|1,mid+1,b,x);    tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;}ll ask(int k,int a,int b){    int l=tr[k].l,r=tr[k].r;    if(a==l&&b==r)return tr[k].sum;    if(tr[k].tag)pd(k);    int mid=(l+r)>>1;    if(b<=mid)return ask(k<<1,a,b);    else if(a>mid)return ask(k<<1|1,a,b);    else return (ask(k<<1,a,mid)+ask(k<<1|1,mid+1,b));}int main(){    n=read();    R1(i,n)aa[i]=read();    build(1,1,n);    q=read();    R1(i,q){        int t,a,b,x;        t=read();        if(t==1){            a=read(),b=read(),x=read();            update(1,a,b,x);            }        else{            a=read(),b=read();            printf("%lld\n",ask(1,a,b));           }    }    return 0;}

zkw线段树

代码来自在被窝里写zkw线段树的神wxjlzbcd,太神了!!!

/* Name:wxjlzbcd Memory:8KB Time:651ms */  #include<cstdio>  #include<cstdlib>  #include<cctype>  #include<cstring>  #define LL long long  LL x,a,b,c,n,m,pre=1;  LL num[524288],numm[1000000];  inline int getc()   {      static const int L = 1 << 15;      static char buf[L] , *S = buf , *T = buf;      if (S == T) {          T = (S = buf) + fread(buf , 1 , L , stdin);          if (S == T)              return EOF;      }      return *S++;  }  inline int getint() {      static char c;      while(!isdigit(c = getc()) && c != '-');      bool sign = (c == '-');      int tmp = sign ? 0 : c - '0';      while(isdigit(c = getc()))          tmp = (tmp << 1) + (tmp << 3) + c - '0';      return sign ? -tmp : tmp;  }  inline char getch() {      char c;      while((c = getc()) != 'Q' && c != 'C');      return c;  }  inline void add(int a,int b)  {      num[a+=pre]+=b;      numm[a]=(a-pre)*num[a];      a>>=1;      while(a)      {          num[a]=num[a<<1]+num[(a<<1)+1];          numm[a]=numm[a<<1]+numm[(a<<1)+1];          a>>=1;      }  }  inline LL query(int a,int b)  {      LL ans=0;      a+=pre-1;      b+=pre+1;      while(a^b^1)      {          if(~a&1)              ans+=num[a^1];          if(b&1)              ans+=num[b^1];          a>>=1;          b>>=1;      }      return ans;  }  inline LL nquery(int a,int b)  {      LL ans=0;      a+=pre-1;      b+=pre+1;      while(a^b^1)      {          if(~a&1)              ans+=numm[a^1];          if(b&1)              ans+=numm[b^1];          a>>=1;          b>>=1;      }      return ans;  }  int main()  {      int i;      n=getint();      while(pre<=n)          pre<<=1;      for(i=pre+1;i<=pre+n;++i)          num[i]=getint();      for(i=pre+n;i>pre;--i)      {          num[i]-=num[i-1];          numm[i]=(i-pre)*num[i];      }      for(i=pre-1;i>=1;--i)      {          num[i]=num[i<<1]+num[(i<<1)+1];          numm[i]=numm[i<<1]+numm[(i<<1)+1];      }  /*  for(i=1;i<=pre+n;++i)         printf("%d ",num[i]);*/      m=getint();      for(i=1;i<=m;++i)      {          x=getint();          if(x==1)          {              a=getint(),b=getint(),c=getint();              add(a,c),add(b+1,-c);          }          else          {              a=getint(),b=getint();              printf("%lld\n",(query(1,b)*(b+1)-nquery(1,b))-query(1,a-1)*a+nquery(1,a-1));             }      }      return 0;  }  

树状数组

参考了某神的花神游历各国的写法,然后就会bit的区间修改了
= =等等这个和zkw好像

由于本题更新的时候是区间更新
所以不能直接去一个个更新区间内的点,肯定会超时
对于每次更新C(a,b,d)表示区间[a,b]内的值增加d
用ans[a]表示a~n区间元素增加的值,所以对于C(a,b,d)有:ans[a]+=d,ans[b+1]-=d;
则每次询问的时候Q(a,b),求a~b的和SUM=sum(a,b)+ans[a](b-a+1)+ans[a+1](b-a)…+ans[b]//sum(a,b)表示a,b的和
Sum=sum(a,b)+sum(ans[a+t](b-a-t+1))=sum(a,b)+sum(ans[i](b-i+1));a<=i<=b;
Sum=sum(a,b)+(b+1)*sum(ans[i])-sum(ans[i]*i);//1~b所以(b+1)*sum(ans[i]),1~a-1则a*sum(ans[i])
所以可以用两个树状数组分别表示ans[i]的前缀和 和 ans[i]*i的前缀和

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<bits/stdc++.h>#define R0(i,n) for(int i=0;i<n;++i)#define R1(i,n) for(int i=1;i<=n;++i)#define CLR(x,c) memset(x,c,sizeof x)using namespace std;typedef long long LL;inline int getc() {    static const int L = 1 << 15;    static char buf[L] , *S = buf , *T = buf;    if (S == T) {        T = (S = buf) + fread(buf , 1 , L , stdin);        if (S == T)            return EOF;    }    return *S++;}inline int read() {    static char c;    while(!isdigit(c = getc()) && c != '-');    bool sign = (c == '-');    int tmp = sign ? 0 : c - '0';    while(isdigit(c = getc()))        tmp = (tmp << 1) + (tmp << 3) + c - '0';    return sign ? -tmp : tmp;}LL n,q;LL sum[200005],c1[200005],c2[200005];inline LL lowbit(LL x){    return x&(-x);}void update(LL x,LL d,LL *c){    while(x<=n){        c[x]+=d;        x+=lowbit(x);    }}LL query(LL x,LL *c){    LL sum=0;    while(x>0){        sum+=c[x];        x-=lowbit(x);    }    return sum;}int main(){    int op;    LL x,y,d;    n=read();    R1(i,n)sum[i]=read(),sum[i]+=sum[i-1];    q=read();    R0(i,q){            op=read();            if(op==1){//ans[x]+=d,ans[y+1]-=d                x=read(),y=read(),d=read();                update(x,d,c1),update(y+1,-d,c1);                update(x,x*d,c2),update(y+1,-(y+1)*d,c2);            }            else{                x=read(),y=read();                printf("%lld\n",sum[y]-sum[x-1]+query(y,c1)*(y+1)-query(x-1,c1)*x-query(y,c2)+query(x-1,c2));            }    }    return 0;}

时间对比

这里写图片描述
从上到下分别是zkw,bit,普通线段树
别问我素质为何这么低= =

2 0
原创粉丝点击