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
- codevs1082 线段树练习3
- 【codevs1082】线段树练习 3
- [CODEVS1082]线段树练习 3
- Codevs1082 线段树练习 3 Lazy
- codevs1082线段树练习3(线段树)
- [CodeVS1082] 线段树练习3(区间修改+询问区间和)
- Codevs1082 线段树练习三(树状数组)
- 线段树练习3
- 线段树练习3
- 线段树练习3
- Codevs_P1082 线段树练习3(线段树)
- 【wikioi1082】 线段树练习 3
- wikioi1082【线段树练习 3 】
- codevs线段树练习3
- <线段树系列3> codevs 1082 线段树练习3
- 【Codevs】1082 线段树练习 3 && 线段树模板
- Codevs 1082 线段树练习 3(线段树&&分块)
- 【线段树+lazy优化】1082线段树练习3
- 初中生可能学好编程么?
- codeforces 515d Drazil and Tiles
- Subsets
- Java中的TreeMap、Comparable、Comparator
- 历届试题 兰顿蚂蚁
- codevs1082 线段树练习3
- 《数据结构编程实验》 1.5.4A Contesting Decision
- oracle中解决被锁定的scott用户的方法。
- 【Unity】查看、使用Untiy内部库和方法
- Ajax使用范例
- Java与数据库对应的日期类型
- Palindrome Partitioning
- HDU 4009 Transfer water(不定根最小树形图)
- 新年快乐