uva1400 "Ray, Pass me the dishes!"
If you encounter something you don't understand while reading this article, ask in the comments section, or skip over it. An overview of segment trees
It's a black topic on luogu... QAQ (but it's a line segment tree template title, qwq)
Main idea of the title: Give a long n integer sequence D, answer m questions, find (x,y) for a <=x<=y<=b and D x+D x+1+...+Dy max.If there are multiple sets of answers, choose the one with the smallest dictionary order (that is, the smallest x, y).
Here's a little bit of nonsense (little bit of explanatory code)
Since it is obvious that to output two numbers (x,y) it is not possible to use normal return values, here you choose to use a struct type data as the return value, whose L and R are the required x,y
To be able to compare sizes (dictionary order), the rainbow-like overloaded operator, Friend Function, has been written.(pair can also be used)
Prefixes and sum[] are also used for optimization.
Note that if you use overloaded operators, you can choose to define a val or prefix and,
But if you use pair, you must override the overloaded operator (because you cannot have three quantities).
You can also choose to write a comparison function manually.
struct data{ int l,r; long long val(){return sum[r]-sum[l-1];} friend bool operator > (data a,data b){ return a.val()>b.val()||(a.val()==b.val()&&(a.l<b.l||(a.l==b.l&&a.r<b.r))); } friend bool operator < (data a,data b){ return a.val()<b.val()||(a.val()==b.val()&&(a.l>b.l||(a.l==b.l&&a.r>b.r))); } };
defmax is a data type max....
data defmax(data a,data b){ return a>b?a:b; }
Maybe that would be better?(That's all it takes... woc wants to compare other types?)
auto defmax(auto a,auto b){ return a>b?a:b; }
pushup:
Maxn Compare Left, Right, Middle
pre Compare Left, Left+Right
suf same
void pushup(int rt){ Maxn[rt]=defmax(defmax(Maxn[LS],Maxn[RS]),(data){suf[LS].l,pre[RS].r}); //left right and middle pre[rt]=defmax(pre[LS],(data){pre[LS].l,pre[RS].r}); suf[rt]=defmax(suf[RS],(data){suf[LS].l,suf[RS].r}); //Note that size is important here, not interval length }
Build, is build
void build(int rt,int l,int r){ if(l==r){ pre[rt]=suf[rt]=Maxn[rt]=(data){l,r}; return; }int mid=l+r>>1; build(LS,l,mid); build(RS,mid+1,r); pushup(rt); return; }
query
If it contains the maximum interval that returns the node directly
Do not judge left or right within an interval (whole interval)
Look for the precursor in the middle, follow on the left, and assemble on the right, larger than pure left and right
data query(int rt,int l,int r,int x,int y){ if(x<=l&&y>=r)return Maxn[rt]; int mid=l+r>>1; if(y<=mid) //Left Son return query(LS,l,mid,x,y); if(x>mid) //Right Son return query(RS,mid+1,r,x,y); //In the middle data a=defmax(query(LS,l,mid,x,y),query(RS,mid+1,r,x,y)); data b=(data){asksuf(LS,l,mid,x,y).l,askpre(RS,mid+1,r,x,y).r}; return defmax(a,b); }
Find Front/Back (Symmetric Edition)
Keep looking right, go left, and make sure you just piece it up
data asksuf(int rt,int l,int r,int x,int y){ //Find successors in the left subtree(r == y) if(suf[rt].l>=x)return suf[rt]; //This interval must follow > Son's Succession int mid=l+r>>1; if(x>mid)return asksuf(RS,mid+1,r,x,y); return defmax((data){asksuf(LS,l,mid,x,y).l,r},suf[RS]); } data askpre(int rt,int l,int r,int x,int y){ if(pre[rt].r<=y)return pre[rt]; int mid=l+r>>1; if(y<=mid)return askpre(LS,l,mid,x,y); return defmax((data){l,askpre(RS,mid+1,r,x,y).r},pre[LS]); }
Code
QAQ friend didn't even highlight it and added an eco-friendly green of its own
/*uva1400*/
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> using namespace std; const int N=2e6+3; long long sum[N],a[N]; struct data{ int l,r; long long val(){return sum[r]-sum[l-1];} friend bool operator > (data a,data b){ return a.val()>b.val()||(a.val()==b.val()&&(a.l<b.l||(a.l==b.l&&a.r<b.r))); } friend bool operator < (data a,data b){ return a.val()<b.val()||(a.val()==b.val()&&(a.l>b.l||(a.l==b.l&&a.r>b.r))); } }; data defmax(data a,data b){ return a>b?a:b; } namespace Segment_Tree{ #define LS (rt<<1) #define RS (LS|1) data pre[N<<2],suf[N<<2],Maxn[N<<2]; //Precursor followed by maximum subsection and void pushup(int rt){ Maxn[rt]=defmax(defmax(Maxn[LS],Maxn[RS]),(data){suf[LS].l,pre[RS].r}); //left right and middle pre[rt]=defmax(pre[LS],(data){pre[LS].l,pre[RS].r}); suf[rt]=defmax(suf[RS],(data){suf[LS].l,suf[RS].r}); //Note that size is important here, not interval length } void build(int rt,int l,int r){ if(l==r){ pre[rt]=suf[rt]=Maxn[rt]=(data){l,r}; return; }int mid=l+r>>1; build(LS,l,mid); build(RS,mid+1,r); pushup(rt); return; } data asksuf(int rt,int l,int r,int x,int y){ //Find successors in the left subtree(r == y) if(suf[rt].l>=x)return suf[rt]; //This interval must follow > Son's Succession int mid=l+r>>1; if(x>mid)return asksuf(RS,mid+1,r,x,y); return defmax((data){asksuf(LS,l,mid,x,y).l,r},suf[RS]); } data askpre(int rt,int l,int r,int x,int y){ if(pre[rt].r<=y)return pre[rt]; int mid=l+r>>1; if(y<=mid)return askpre(LS,l,mid,x,y); return defmax((data){l,askpre(RS,mid+1,r,x,y).r},pre[LS]); } data query(int rt,int l,int r,int x,int y){ if(x<=l&&y>=r)return Maxn[rt]; int mid=l+r>>1; if(y<=mid) //Left Son return query(LS,l,mid,x,y); if(x>mid) //Right Son return query(RS,mid+1,r,x,y); //In the middle data a=defmax(query(LS,l,mid,x,y),query(RS,mid+1,r,x,y)); data b=(data){asksuf(LS,l,mid,x,y).l,askpre(RS,mid+1,r,x,y).r}; return defmax(a,b); } } using namespace Segment_Tree; int main(){ int n,m,x,y,Case=0; data ans; while(scanf("%d%d", &n, &m)!=EOF){ printf("Case %d:\n",++Case); for(int i=1;i<=n;++i){ scanf("%lld",&a[i]); sum[i]=a[i]+sum[i-1]; //sum Will overwrite the previous, may not initialize } build(1,1,n); while(m--){ scanf("%d%d",&x,&y); ans=query(1,1,n,x,y); printf("%d %d\n",ans.l,ans.r); } } return 0; }