T1 维护lmax 向左延伸的最大值,rmax同理,sum区间和,ans答案。
转移见operator +
#include<bits/stdc++.h> #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) #define int long long using namespace std; const int N =(int)1e5+10; struct TREE { int lef,rig,sum,ans; int l,r; void clear() {lef=rig=sum=ans=0;} void debug() { printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans); } }tr[N<<2]; int a[N]; TREE operator + (TREE l,TREE r) { TREE rt;rt.clear(); rt.l=l.l;rt.r=r.r; rt.lef=max(l.sum+r.lef,l.lef); rt.rig=max(r.sum+l.rig,r.rig); rt.sum=l.sum+r.sum; rt.ans=max(l.ans,max(l.rig+r.lef,r.ans)); return rt; } void build(int l,int r,int rt) { tr[rt].l=l,tr[rt].r=r; if(l==r) { tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l]; return ; } build(l,mid,ls),build(mid+1,r,rs); tr[rt]=tr[ls]+tr[rs]; } TREE query(int l,int r,int rt,int L,int R) { if(L==l&&r==R) { return tr[rt]; } if(R<=mid) return query(l,mid,ls,L,R); else if(L>mid) return query(mid+1,r,rs,L,R); else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R); } int n,m; main() { cin>>n; for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n,1); cin>>m; for(int i=1;i<=m;i++) { int l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",query(1,n,1,l,r).ans); } return 0; }
T2.维护区间去重之后最大值。
同多校2017#404记录前一个状态,然后一个一个加入,维护一个后缀和
#include<bits/stdc++.h> #define int long long #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) #define hash H_sh using namespace std; const int N =(int)2e5+10; struct TREE { int max,lazy,pre_max,pre_lazy; int l,r; TREE() {max=lazy=pre_lazy=pre_max=0;} }tr[N<<2]; int a[N]; struct QUERY { int l,r,id; bool operator <(const QUERY &rhs) const { return r<rhs.r; } }p[N]; int n,m,ans[N],pre[N]; void pushup(int rt) { tr[rt].max=max(tr[ls].max,tr[rs].max); tr[rt].pre_max=max(tr[ls].pre_max,tr[rs].pre_max); } void pushdown(int rt) {//×¢ÒâÕâ¸öµÄpushdownµÄÕæÕýµÄÒâÒ壬ÊÇÏ´«±ê¼Ç£¬Ï´«¡£ if(!(tr[rt].lazy|tr[rt].pre_lazy)) return ; tr[ls].pre_lazy=max(tr[ls].pre_lazy,tr[ls].lazy+tr[rt].pre_lazy); tr[rs].pre_lazy=max(tr[rs].pre_lazy,tr[rs].lazy+tr[rt].pre_lazy); tr[ls].pre_max=max(tr[ls].pre_max,tr[ls].max+tr[rt].pre_lazy); tr[rs].pre_max=max(tr[rs].pre_max,tr[rs].max+tr[rt].pre_lazy); tr[ls].lazy+=tr[rt].lazy,tr[rs].lazy+=tr[rt].lazy; tr[ls].max+=tr[rt].lazy,tr[rs].max+=tr[rt].lazy; tr[rt].lazy=tr[rt].pre_lazy=0; } void update(int l,int r,int rt,int L,int R,int C) { tr[rt].l=l,tr[rt].r=r; if(L==l&&r==R) { tr[rt].max+=C;tr[rt].lazy+=C; tr[rt].pre_max=max(tr[rt].pre_max,tr[rt].max); tr[rt].pre_lazy=max(tr[rt].pre_lazy,tr[rt].lazy); return ; } pushdown(rt); if(R<=mid) update(l,mid,ls,L,R,C); else if(L>mid) update(mid+1,r,rs,L,R,C); else update(l,mid,ls,L,mid,C),update(mid+1,r,rs,mid+1,R,C); pushup(rt); } int query(int l,int r,int rt,int L,int R) { if(l==L&&R==r) return tr[rt].pre_max; pushdown(rt); if(R<=mid) return query(l,mid,ls,L,R); else if(L>mid) return query(mid+1,r,rs,L,R); else return max(query(l,mid,ls,L,mid),query(mid+1,r,rs,mid+1,R)); } int hash(int a) {return a+(int)1e5;} main() { cin>>n; for(int i=1;i<=n;i++) scanf("%lld",&a[i]); cin>>m; for(int i=1;i<=m;i++) scanf("%lld%lld",&p[i].l,&p[i].r),p[i].id=i; sort(p+1,p+m+1); for(int i=1,pos=1;i<=n;i++) { update(1,n,1,pre[hash(a[i])]+1,i,a[i]); pre[hash(a[i])]=i; while(pos<=m&&p[pos].r==i) ans[p[pos].id]=query(1,n,1,p[pos].l,p[pos].r),pos++; if(pos>m) break; } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
T3.同t1多了一个修改
#include<bits/stdc++.h> #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) #define int long long using namespace std; const int N =(int)1e5+10; struct TREE { int lef,rig,sum,ans; int l,r; void clear() {lef=rig=sum=ans=0;} void debug() { printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans); } }tr[N<<2]; int a[N]; TREE operator + (TREE l,TREE r) { TREE rt;rt.clear(); rt.l=l.l;rt.r=r.r; rt.lef=max(l.sum+r.lef,l.lef); rt.rig=max(r.sum+l.rig,r.rig); rt.sum=l.sum+r.sum; rt.ans=max(l.ans,max(l.rig+r.lef,r.ans)); return rt; } void build(int l,int r,int rt) { tr[rt].l=l,tr[rt].r=r; if(l==r) { tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l]; return ; } build(l,mid,ls),build(mid+1,r,rs); tr[rt]=tr[ls]+tr[rs]; } TREE query(int l,int r,int rt,int L,int R) { if(L==l&&r==R) return tr[rt]; if(R<=mid) return query(l,mid,ls,L,R); else if(L>mid) return query(mid+1,r,rs,L,R); else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R); } void update(int l,int r,int rt,int L,int C) { if(l==r) {tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=C;return ;} if(L<=mid)update(l,mid,ls,L,C); else update(mid+1,r,rs,L,C); tr[rt]=tr[ls]+tr[rs]; } int n,m; main() { cin>>n; for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n,1); cin>>m; for(int i=1;i<=m;i++) { int f,l,r; scanf("%lld%lld%lld",&f,&l,&r); if(f) printf("%lld\n",query(1,n,1,l,r).ans); else update(1,n,1,l,r); } return 0; }
T4.区间开方求和,由于发现sqrt(1e18)嵌套6重向下取整为1,于是用线段树记录2一个区间还要不要暴力修改,需要的话暴力sqrt就行了。
#include<bits/stdc++.h> #define int long long #define cls(a) memset(a,0,sizeof(a)) #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) using namespace std; const int N =(int)1e6+10; int sum[N],n,m,a[N],L[N],R[N]; void build(int l,int r,int rt) { L[rt]=l,R[rt]=r; if(l==r) {sum[rt]=a[l];return;} build(l,mid,ls),build(mid+1,r,rs); sum[rt]=sum[ls]+sum[rs]; } void update(int l,int r,int rt,int L,int R) { // cout<<l<<" "<<r<<" "<<L<<" "<<R<<"\n"; if(r-l+1==sum[rt]) return ; if(l==r) {sum[rt]=(int)sqrt(sum[rt]+0.0);return ;}//Ò»¶¨ÒªÊÇÒ¶×Ó½Úµã if(R<=mid) update(l,mid,ls,L,R); else if(L>mid) update(mid+1,r,rs,L,R); else update(l,mid,ls,L,mid),update(mid+1,r,rs,mid+1,R); sum[rt]=sum[ls]+sum[rs]; } int query(int l,int r,int rt,int L,int R) { if(l==L&&r==R) return sum[rt]; if(R<=mid) return query(l,mid,ls,L,R); else if(L>mid) return query(mid+1,r,rs,L,R); else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R); } void init() { cls(sum); } void debug(int l,int r,int rt) { if(l==r) {printf("%lld ",sum[rt]);return;} debug(l,mid,ls),debug(mid+1,r,rs); // sum[rt]=sum[ls]+sum[rs]; } main() { int kase=0; while(cin>>n) { init(); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n,1); // for(int i=1;i<=20;i++) // if(L[i]) // printf("%d %d %d \n",L[i],R[i],sum[i]); cin>>m;printf("Case #%lld:\n",++kase); for(int i=1;i<=m;i++) { int f,l,r; scanf("%lld%lld%lld",&f,&l,&r); if(l>r) swap(l,r); if(!f) update(1,n,1,l,r); else printf("%lld\n",query(1,n,1,l,r)); // debug(1,n,1); } puts(""); } return 0; }
分块也是一样的道理。记录一个块要不要sqrt
#include<bits/stdc++.h> #define maxn 400000 #define int long long #define cls(a) memset(a,0,sizeof(a)) using namespace std; int read() { int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c==‘-‘) f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();} return x*f; } int v[maxn],atag[maxn],bl[maxn],n,blo,sum[maxn],m,flag[maxn]; void solve(int x) { if(flag[x]) return; flag[x]=1; sum[x]=0; for(int i=(x-1)*blo+1;i<=x*blo;i++) { v[i]=sqrt(v[i]),sum[x]+=v[i]; if(v[i]>1) flag[x]=0; } } void update(int a,int b) { for(int i=a;i<=min(bl[a]*blo,b);i++) sum[bl[a]]-=v[i],v[i]=sqrt(v[i]),sum[bl[a]]+=v[i]; if(bl[a]!=bl[b]) { for(int i=(bl[b]-1)*blo+1;i<=b;i++) sum[bl[b]]-=v[i],v[i]=sqrt(v[i]),sum[bl[b]]+=v[i]; } for(int i=bl[a]+1;i<=bl[b]-1;i++) solve(i); } int query(int a,int b) { int ans=0; for(int i=a;i<=min(bl[a]*blo,b);i++) ans+=v[i]; if(bl[a]!=bl[b]) { for(int i=(bl[b]-1)*blo+1;i<=b;i++) ans+=v[i]; } for(int i=bl[a]+1;i<=bl[b]-1;i++) ans+=sum[i]; return ans; } main() { // freopen("1012.out","r",stdin); // freopen("1.txt","w",stdout); int kase=0; while(~scanf("%lld",&n)&&n) { printf("Case #%lld:\n",++kase); cls(v),cls(sum),cls(flag);cls(atag);cls(bl); blo=sqrt(n); for(int i=1;i<=n;i++) v[i]=read(),bl[i]=(i-1)/blo+1, sum[bl[i]]+=v[i]; m=read(); for(int i=1;i<=m;i++) { int f=read(),a=read(),b=read(); if(a>b) swap(a,b); if(f==0) update(a,b); else printf("%lld\n",query(a,b)); } puts(""); } return 0; }
小坑,由于题目说的是x~y所以可能x>y需要swap一下。
T5.给定l,r的取值范围,求l~r和最大
分类讨论,具体见main函数。
小细节注意
要保证点在区间中,这个区间的完整性很重要,要注意如果选lmax那么就是至少选一个元素。
#include<bits/stdc++.h> #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) //#define int long long #define root 1,n,1 using namespace std; const int N =(int)1e5+10; struct TREE { int lef,rig,sum,ans; int l,r; void clear() {lef=rig=sum=ans=0;} void debug() { printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans); } }tr[N<<2],paste; int a[N],t; TREE operator + (TREE l,TREE r) { TREE rt;rt.clear(); rt.l=l.l;rt.r=r.r; rt.lef=max(l.sum+r.lef,l.lef); rt.rig=max(r.sum+l.rig,r.rig); rt.sum=l.sum+r.sum; rt.ans=max(l.ans,max(l.rig+r.lef,r.ans)); return rt; } void build(int l,int r,int rt) { tr[rt].l=l,tr[rt].r=r; if(l==r) { tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l]; return ; } build(l,mid,ls),build(mid+1,r,rs); tr[rt]=tr[ls]+tr[rs]; } TREE query(int l,int r,int rt,int L,int R) { if(L>R) return paste; if(L==l&&r==R) return tr[rt]; if(R<=mid) return query(l,mid,ls,L,R); else if(L>mid) return query(mid+1,r,rs,L,R); else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R); } void update(int l,int r,int rt,int L,int C) { if(l==r) {tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=C;return ;} if(L<=mid)update(l,mid,ls,L,C); else update(mid+1,r,rs,L,C); tr[rt]=tr[ls]+tr[rs]; } int n,m; main() { paste.clear();cin>>t; for(;t;t--) { cin>>n; memset(tr,0,sizeof(tr));memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(root); cin>>m; for(int i=1;i<=m;i++) { int x1,x2,y1,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(y1<x2) { printf("%d\n",query(root,x1,y1).rig+query(root,y1+1,x2-1).sum+query(root,x2,y2).lef); } else { int m1=query(root,x2,y1).ans; int m2=query(root,x2,y2).lef+query(root,x1,x2-1).rig; int m3=query(root,x1,y1).rig+query(root,y1+1,y2).lef; // cout<<query(root,x1,x2-1).rig<<" "<<query(root,y1+1,y2).lef<<"\n"; printf("%d\n",max(max(m1,m2),m3)); } } } return 0; }
后面的3题好像是splay啊,还是不怎么会写,以后再说吧,先挖一个坑。
最后来一发二维树状数组poj2155具体可以看《浅谈信息学竞赛中的“0”和“1”》这篇论文很详细。
一个小小的下标搞了好久。。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cassert> #define lowbit(_x) (_x&(-_x)) using namespace std; int n,m,x1,x2,y1,y2,t,fst=187415157; int sum[1100][1100]; void U(int x,int y,int val) { for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=n;j+=lowbit(j)) sum[i][j]+=val; } int query(int x,int y) { int ans=0; for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j)) ans+=sum[i][j]; return ans; } char s[20]; main() { cin>>t; for(;t;t--){ if(!fst)puts("");fst=0; memset(sum,0,sizeof(sum)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]==‘C‘) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),U(x1,y1,1),U(x1,y2+1,1),U(x2+1,y1,1),U(x2+1,y2+1,1); else scanf("%d%d",&x1,&y1),printf("%d\n",query(x1,y1)%2); } } }
时间: 2024-10-11 17:51:16