ACM入门之【线段树习题】
生活随笔
收集整理的這篇文章主要介紹了
ACM入门之【线段树习题】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- 1275. 最大數【單點修改 區間最大】
- 245. 你能回答這些問題嗎【單點修改 / 區間內的最大連續字段】
- 246. 區間最大公約數【區間修改 區間最大公約數】
- P3372 【模板】線段樹 1【區間修改,區間查詢】
- P2574 XOR的藝術【區間求1的個數 區間取反】
- 247. 亞特蘭蒂斯【掃描線 求矩陣的面積】
1275. 最大數【單點修改 區間最大】
#include<bits/stdc++.h> using namespace std; const int N=1e5*2+10; struct node{int l,r,v;}tr[N*4]; int m,p; void build(int u,int l,int r)//建樹 {tr[u]={l,r};if(l==r) return;int mid=tr[u].l+tr[u].r>>1;build(u*2,l,mid);build(u*2+1,mid+1,r); } void pushup(int u) {tr[u].v=max(tr[u*2].v,tr[u*2+1].v); } int query(int u,int l,int r) {if(tr[u].l>=l&&tr[u].r<=r) return tr[u].v;//包含else{int v=0,mid=(tr[u].l+tr[u].r)/2;if(l<=mid) v=max(v,query(u*2,l,r));//左邊有交集if(r>=mid+1) v=max(v,query(u*2+1,l,r));//右邊有交集return v;} } void modify(int u,int x,int v) //u是根,x是位置,v是值 {if(tr[u].l==x&&tr[u].r==x) tr[u].v=v;//葉子else{int mid=tr[u].l+tr[u].r>>1;if(x<=mid) modify(u*2,x,v);else modify(u*2+1,x,v);pushup(u);} } int main(void) {cin>>m>>p;build(1,1,m);int last=0,n=0;for(int i=0;i<m;i++){char op; cin>>op;if(op=='Q'){int x; cin>>x;last=query(1,n-x+1,n);cout<<last<<endl;}else{int x; cin>>x;modify(1,n+1,(1ll*x+last)%p);n++;}}return 0; }245. 你能回答這些問題嗎【單點修改 / 區間內的最大連續字段】
#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; struct node {int l,r;int sum,tmax,lmax,rmax;//sum: 區間和//tmax:整個區間的最大子段和//lmax:從左端點起的向右的最大子段和//rmax:從右端點起的向左的最大子段和 }tr[N*4]; int a[N],n,m; void push(node& a,node& l,node& r) {a.sum=l.sum+r.sum;a.tmax=max({l.tmax,r.tmax,l.rmax+r.lmax,l.sum+r.lmax,r.sum+l.rmax,});a.lmax=max({l.lmax,l.sum+r.lmax});a.rmax=max({r.rmax,r.sum+l.rmax}); } void pushup(int u) {push(tr[u],tr[u*2],tr[u*2+1]); } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,a[l],a[l],a[l],a[l]};else{tr[u]={l,r};int mid=l+r>>1;build(u*2,l,mid),build(u*2+1,mid+1,r);pushup(u);} } void modify(int u,int x,int v) {if(tr[u].l==x&&tr[u].r==x) {tr[u]={x,x,v,v,v,v};}else{int mid=(tr[u].l+tr[u].r)/2;if(mid>=x) modify(u*2,x,v);else modify(u*2+1,x,v);pushup(u);} } node query(int u,int l,int r) {if(l<=tr[u].l&&tr[u].r<=r) return tr[u];else {int mid=(tr[u].l+tr[u].r)/2;if(mid>=r) return query(u*2,l,r);else if(l>mid) return query(u*2+1,l,r);else{auto left=query(u*2,l,r);auto right=query(u*2+1,l,r);node res;push(res,left,right);return res;}} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);for(int i=0;i<m;i++){int op,x,y; cin>>op>>x>>y;if(op==1){if(x>y) swap(x,y);auto temp=query(1,x,y);cout<<temp.tmax<<endl;}else modify(1,x,y);}return 0; }246. 區間最大公約數【區間修改 區間最大公約數】
上述題解的原處
P3372 【模板】線段樹 1【區間修改,區間查詢】
#include<bits/stdc++.h> using namespace std; typedef long long int LL; const int N=1e5+10; struct node {int l,r;LL sum,add; }tr[N*4]; LL a[N],n,m; void pushup(int u) {tr[u].sum=tr[u*2].sum+tr[u*2+1].sum; } void pushdown(int u)//根節點更新,子結點 {auto &ans=tr[u];auto &l=tr[u*2];auto &r=tr[u*2+1];if(ans.add){l.sum+=(l.r-l.l+1)*ans.add;r.sum+=(r.r-r.l+1)*ans.add;l.add+=ans.add;r.add+=ans.add;ans.add=0;} } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,a[l],0};else{int mid=(l+r)/2;tr[u]={l,r};build(u*2,l,mid),build(u*2+1,mid+1,r);pushup(u);} } void modify(int u,int l,int r,int d) {if(l<=tr[u].l&&tr[u].r<=r){tr[u].sum+=1ll*(tr[u].r-tr[u].l+1)*d;tr[u].add+=d;}else{pushdown(u);int mid=(tr[u].l+tr[u].r)/2;if(l<=mid) modify(u*2,l,r,d);if(r>=mid+1) modify(u*2+1,l,r,d);pushup(u);} } LL query(int u,int l,int r) {if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;else{pushdown(u);LL sum=0;int mid=(tr[u].l+tr[u].r)/2;if(l<=mid) sum+=query(u*2,l,r);if(r>=mid+1) sum+=query(u*2+1,l,r);return sum;} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);for(int i=0;i<m;i++){int op; cin>>op;if(op==1){int l,r,d; cin>>l>>r>>d;modify(1,l,r,d);}else{int l,r; cin>>l>>r;cout<<query(1,l,r)<<endl;}}return 0; }P2574 XOR的藝術【區間求1的個數 區間取反】
#include<bits/stdc++.h> using namespace std; const int N=1e5*2+10; struct node {int l,r;int sum,add;//sum 1的個數 }tr[N*4]; int n,m,a[N]; char s[N]; void pushup(int u) {tr[u].sum=tr[u*2].sum+tr[u*2+1].sum; } void pushdown(int u) {if(tr[u].add) {tr[u*2].sum=(tr[u*2].r-tr[u*2].l+1)-tr[u*2].sum;tr[u*2+1].sum=(tr[u*2+1].r-tr[u*2+1].l+1)-tr[u*2+1].sum;tr[u*2].add^=1;tr[u*2+1].add^=1;tr[u].add=0; } } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,a[l],0};else{tr[u]={l,r};int mid=(l+r)/2;build(u*2,l,mid),build(u*2+1,mid+1,r);pushup(u);} } void modity(int u,int l,int r) {if(l<=tr[u].l&&tr[u].r<=r){tr[u].sum=(tr[u].r-tr[u].l+1)-tr[u].sum;tr[u].add^=1;}else{pushdown(u);int mid=(tr[u].l+tr[u].r)/2;if(l<=mid) modity(u*2,l,r);if(r>=mid+1) modity(u*2+1,l,r);pushup(u);} } int query(int u,int l,int r) {if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;else{pushdown(u);int mid=(tr[u].l+tr[u].r)/2;int sum=0;if(l<=mid) sum+=query(u*2,l,r);if(r>=mid+1) sum+=query(u*2+1,l,r);return sum;} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>s[i];for(int i=1;i<=n;i++) a[i]=s[i]-'0';build(1,1,n);for(int i=0;i<m;i++){int op,l,r; cin>>op>>l>>r;if(op==0) modity(1,l,r);else cout<<query(1,l,r)<<endl;}return 0; }247. 亞特蘭蒂斯【掃描線 求矩陣的面積】
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n; struct Segment {double x,y1,y2;bool operator< (const Segment &t)const{return x<t.x;}int k; }seg[N*2]; struct Node {int l,r;int cnt;//當前區間被覆蓋的次數double len;//子區間總共被覆蓋的長度 }tr[N*8]; vector<double>ys;int find(double y) {return lower_bound(ys.begin(),ys.end(),y)-ys.begin(); }void pushup(int u) {if(tr[u].cnt) tr[u].len=ys[tr[u].r+1]-ys[tr[u].l];else if(tr[u].l!=tr[u].r){tr[u].len=tr[u*2].len+tr[u*2+1].len; }else tr[u].len=0; }void build(int u,int l,int r) {tr[u]={l,r,0,0};if(l!=r){int mid=(l+r)/2;build(u*2,l,mid),build(u*2+1,mid+1,r);} }void modify(int u,int l,int r,int k) {if(l<=tr[u].l&&tr[u].r<=r){tr[u].cnt+=k;pushup(u);}else{int mid=(tr[u].l+tr[u].r)/2;if(l<=mid) modify(u*2,l,r,k);if(r>mid) modify(u*2+1,l,r,k);pushup(u);} }int main() {int t=1;while(scanf("%d",&n),n){ys.clear();for(int i=0,j=0;i<n;i++){double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);seg[j++]={x1,y1,y2,1};seg[j++]={x2,y1,y2,-1};ys.push_back(y1),ys.push_back(y2);}sort(ys.begin(),ys.end());ys.erase(unique(ys.begin(),ys.end()),ys.end());build(1,0,ys.size()-2);sort(seg,seg+n*2);double res=0;for(int i=0;i<n*2;i++){if(i>0) res+=tr[1].len*(seg[i].x-seg[i-1].x);modify(1,find(seg[i].y1),find(seg[i].y2)-1,seg[i].k);}printf("Test case #%d\n",t++);printf("Total explored area: %.2lf\n\n", res);} }總結
以上是生活随笔為你收集整理的ACM入门之【线段树习题】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM入门之【线段树】
- 下一篇: 2021算法竞赛入门班第九节课【线段树】