线段树(题集
扶苏学长给我们讲了线段树、树状数组、主席树等数据结构
并发布了练习题单……
题目:
- #A P2574 XOR的艺术
- #B P3372 【模板】线段树 1
- #C P1816 忠诚
- #D P3373 【模板】线段树 2
- #E P1637 三元上升子序列
- #F P1471 方差
- #G P5522 [yLOI2019] 棠梨煎雪
- #H P1558 色板游戏
- #I P6587 超超的序列 加强
- #J P6492 [COCI2010-2011#6] STEP
A:
只需将maketag函数更改为异或和即可
然后tag的更新方式更改
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const long long k=5e5+5; long long a[k]; struct Segment{ long long l,r; long long sum; long long tag; Segment *lef,*rig; Segment(const long long L,const long long R ) { l=L;r=R; tag=0; if(l != r) { int mid=l+r>>1; lef=new Segment(l,mid); rig=new Segment(mid+1,r); sum=lef->sum +rig->sum ; tag=0; } else{ lef=rig=NULL; sum=a[l]; } } inline void maketag(){ sum=(r-l+1)-sum; tag^=1; } void spread() { // if(lef == NULL) lef=new Segment(l,mid); // if(rig == NULL) rig =new Segment(mid+1,r); if(tag==0) return; else { lef->maketag(); rig->maketag(); tag=0; } } inline bool Out(const long long L,const long long R) { return (R<l || r<L ) ;} void change(long long L,long long R) { if(L<=l && r<=R){ maketag(); } else { if(Out(L,R)) return ; else{ spread(); lef->change(L,R); rig->change(L,R); sum=lef->sum+rig->sum; } } } long long ask(long long L,long long R) { if(L<=l && r<=R) return sum; else { if(Out(L,R)) return 0; else{ spread(); return lef->ask(L,R)+rig->ask(L,R); } } } }; Segment *root; int main(void) { long long n,m,q; string str; ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); cin>>n>>m; cin>>str; for(long long i=1;i<=n;i++) { int q=str[i-1]-'0'; a[i]=q; } root=new Segment(1,n); for(long long i=1;i<=m;i++) { long long x,y,z,g; cin>>x>>y>>z; if(x==0){ root->change(y,z); } else { cout<<root->ask(y,z)<<'\n'; } } }
B、D:
模板不多说
C:
该题没有修改,只有询问,所以只维护一个最小值即可
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const long long k=5e5+5; long long a[k]; struct Segment{ long long l,r; long long sum; long long tag; Segment *lef,*rig; Segment(const long long L,const long long R ) { l=L;r=R; tag=0; if(l != r) { int mid=l+r>>1; lef=new Segment(l,mid); rig=new Segment(mid+1,r); sum=min(lef->sum,rig->sum); tag=0; } else{ lef=rig=NULL; sum=a[l]; } } inline bool Out(const long long L,const long long R) { return (R<l || r<L ) ;} long long ask(long long L,long long R) { if(L<=l && r<=R) return sum; else { if(Out(L,R)) return 1<<30; else{ return min(lef->ask(L,R),rig->ask(L,R)); } } } }; Segment *root; int main(void) { long long n,m,q; ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; root=new Segment(1,n); for(long long i=1;i<=m;i++) { long long x,y,z; cin>>x>>y; cout<<root->ask(x,y)<<" "; } }
F:
维护一个区间和与一个区间平方和
再对方差公式进行推导
即可
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=100005; 8 double a[maxn]; 9 int n,q; 10 struct Node{ 11 double v1,v2,tag; 12 int l,r; 13 Node *ls,*rs; 14 Node(const int L,const int R){ 15 l=L,r=R; 16 if(l==r){ 17 tag=0; 18 v1=a[l]; 19 v2=a[l]*a[l];//v2表示序列平方和,初始化为平方 20 rs=ls=NULL; 21 } 22 else{ 23 tag=0; 24 int M=(L+R)>>1; 25 ls=new Node(L,M); 26 rs=new Node(M+1,R); 27 pushup(); 28 } 29 } 30 inline void pushup(){ 31 v1=ls->v1+rs->v1; 32 v2=ls->v2+rs->v2; 33 } 34 inline void pushdown(){ 35 if(tag==0) return; 36 else{ 37 ls->maketag(tag); 38 rs->maketag(tag); 39 tag=0; 40 } 41 } 42 inline void maketag(double w){ 43 v2=v2+(r-l+1)*w*w+2*w*v1;//根据公式计算,注意一定要先更新v2再更新v1,因为更新v2要用到原序列的和 44 v1+=(r-l+1)*w; 45 tag+=w; 46 } 47 inline bool InRange(const int L,const int R){ 48 return (l>=L)&&(r<=R); 49 } 50 inline bool OutofRange(const int L,const int R){ 51 return (l>R)||(r<L); 52 } 53 inline void upd(const int L,const int R,double w){ 54 if(InRange(L,R)){ 55 maketag(w); 56 }else if(!OutofRange(L,R)){ 57 pushdown(); 58 ls->upd(L,R,w); 59 rs->upd(L,R,w); 60 pushup(); 61 } 62 } 63 double qry(const int L,const int R){ 64 if(InRange(L,R)){ 65 return v1; 66 } 67 if(OutofRange(L,R)){ 68 return 0; 69 } 70 else{ 71 pushdown(); 72 return ls->qry(L,R)+rs->qry(L,R); 73 } 74 } 75 double qry1(const int L,const int R){ 76 if(InRange(L,R)){ 77 return v2; 78 } 79 if(OutofRange(L,R)){ 80 return 0; 81 } 82 else{ 83 pushdown(); 84 return ls->qry1(L,R)+rs->qry1(L,R); 85 } 86 } 87 }; 88 int main() 89 { 90 scanf("%d%d",&n,&q); 91 for(int i=1;i<=n;i++){ 92 scanf("%lf",a+i); 93 } 94 Node *rot=new Node(1,n); 95 for(int i=1;i<=q;i++){ 96 int o,x,y; 97 double z; 98 scanf("%lld%d%d",&o,&x,&y); 99 if(x>y){ 100 swap(x,y); 101 } 102 if(o==1){ 103 scanf("%lf",&z); 104 rot->upd(x,y,z); 105 } 106 if(o==2){ 107 printf("%.4lf\n",(rot->qry(x,y))/(y-x+1)); 108 } 109 if(o==3){ 110 double s1=rot->qry1(x,y);//平方和 111 double s2=(rot->qry(x,y))/(y-x+1);//平均数 112 double s3=rot->qry(x,y);//和 113 printf("%.4lf\n",((s1-2*s2*s3+(y-x+1)*s2*s2)/(y-x+1)));//根据公式计算 114 } 115 } 116 return 0; 117 }
G:
多次试验表明,我煎不出来。。。
等扶苏学长来讲吧
H:
本题需要使用状压优化与位运算
初始时将所有颜色用二进制数表示
每次上色将对应的数值更新
下传标记为直接覆盖
上传信息时,将两个数进行或运算
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<ctime> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 9 using namespace std; 10 11 int l, t, o, lf, rt, color; 12 char op; 13 14 struct Node{ 15 int l, r; 16 long long tag, v; 17 Node *ls, *rs; 18 19 inline bool InRange(const int L, const int R){ 20 return (L <= l) && (r <= R); 21 } 22 inline bool OutofRange(const int L, const int R){ 23 return (L > r) || (l > R); 24 } 25 inline void maketag(const long long x){ 26 tag = x;//????????????????? 27 v = x;//?????? 28 } 29 inline void pushdown(){ 30 if(tag == 0) return;//?????????????У????????′????????? 31 ls->maketag(tag); 32 rs->maketag(tag); 33 tag = 0; 34 } 35 inline void pushup(){ 36 /*if(ls != NULL){ 37 v |= ls->v; 38 } 39 if(rs != NULL){ 40 v |= rs->v; 41 }*/ 42 v = (ls->v) | (rs->v); 43 } 44 Node (const int L, const int R){ 45 l = L; 46 r = R; 47 tag = 0; 48 if(L == R){ 49 tag = 0; 50 v = 1 << 1; 51 ls = NULL; 52 rs = NULL; 53 } 54 else { 55 int M = (l + r) >> 1; 56 ls = new Node(l, M); 57 rs = new Node(M + 1, R); 58 pushup(); 59 } 60 } 61 inline void upd(const int L, const int R, const long long x){ 62 if(InRange(L, R)){ 63 maketag(x); 64 } 65 else if(!OutofRange(L, R)){ 66 pushdown(); 67 ls->upd(L, R, x); 68 rs->upd(L, R, x); 69 pushup(); 70 } 71 } 72 inline long long query(const int L, const int R){ 73 if(InRange(L, R)){ 74 return v; 75 } 76 else if(!OutofRange(L, R)){ 77 pushdown(); 78 return ls->query(L, R) | rs->query(L, R); 79 } 80 else return 0; 81 } 82 }; 83 84 inline int bit(const long long n){ 85 int res = 0, n0 = n; 86 while(n0){ 87 res += (n0 & 1); 88 n0 >>= 1; 89 } 90 return res; 91 } 92 93 int main(){ 94 scanf("%d%d%d",&l,&t,&o); 95 Node *rot = new Node(1,l); 96 97 for(int i=1;i<=o;i++){ 98 cin >> op; 99 if(op == 'C'){ 100 scanf("%d%d%d",&lf,&rt,&color); 101 if(lf > rt) swap(lf, rt); 102 rot->upd(lf,rt,(long long)1<<color); 103 } 104 else{ 105 scanf("%d%d",&lf,&rt); 106 if(lf > rt) swap(lf, rt); 107 printf("%d\n",bit(rot->query(lf,rt))); 108 } 109 } 110 111 return 0; 112 }
I、J:
这两个题mod做
E将会在树状数组时进行讲解
另:《棠梨煎雪》可以通过树状数组拿到可观的部分分
-end-