当前进度:20201029 更新至GSS5
GSS1 - Can you answer these queries I
第一题,主要处理不同区间里,最大值,从左边开始的最大值,从右边开始的最大值,总和 这4个点的合并即可,luogu之前做过和这题思路及其类似的就是我,这题也是线段树的题,不过侧重于维护区间连续1的长度,并且需要支持区间修改和区间查询,不过大概思路是可以借鉴的
那么回到本题,既然需要是查询某一段中最大的前缀和,那么就得想如何处理区间合并,假设现在左子区间和右子区间已经确定了最大前缀和,那这一段的最大前缀和,要么是左子区间的最大前缀和,要么是右子区间的最大前缀和,或者,第三种可能,左子区间取右边的一部分,右子区间取左边的一部分,这2部分重新组合,变成当前区间的最大前缀和,所以我们合并2个区间的区间的时候,需要知道三个值,当前最大,当前以左边界为起点的最大,当前以右边界为终点的最大,维护好这三个值即可
总结:一开始就想到思路了,但是写的时候出了点问题,我额外记录了maxsum,lmaxsum,rmaxsum各自的左边界、右边界,但是其实压根不需要(
精简后的代码版本如下
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll a[maxn];
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct Segment_Tree{
struct node{
ll sum;
ll maxsum;;
ll lmaxsum;
ll rmaxsum;
node (){
sum=maxsum=lmaxsum=rmaxsum=0;
}
inline node operator + (const node & b) const
{
node c;
c.sum=sum+b.sum;
c.maxsum=max(rmaxsum+b.lmaxsum,max( maxsum,b.maxsum));
c.lmaxsum=max(lmaxsum,sum+b.lmaxsum);
c.rmaxsum=max(b.rmaxsum,b.sum+rmaxsum);
return c;
}
}t[maxn<<2];
node now;
node query_maxsum(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
{
return t[p];
}
int mid=(l+r)>>1;
if(ql<=mid && mid<qr)
{
return query_maxsum(ls(p),l,mid,ql,qr)+query_maxsum(rs(p),mid+1,r,ql,qr);
}
else
{
if(ql<=mid)
{
return query_maxsum(ls(p),l,mid,ql,qr);
}
else
{
return query_maxsum(rs(p),mid+1,r,ql,qr);
}
}
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p].maxsum=t[p].lmaxsum=t[p].rmaxsum=a[l];
t[p].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
// push_up(p);
t[p]=t[ls(p)]+t[rs(p)];
}
}S1;
int n,m;
int l,r;
int main()
{
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
}
cin>>m;
S1.build(1,1,n);
while(m--)
{
cin>>l>>r;
S1.now=S1.query_maxsum(1,1,n,l,r);
cout<<S1.now.maxsum<<"\n";
}
return 0;
}
GSS2 - Can you answer these queries II
第二题,给出n个数字,q次询问,求最大子段和,而相同的数字只算一次。
我们可以注意到,单独查看当前询问时,范围为
[
l
,
r
]
[l,r]
[l,r],也就是a[r]之后的数字压根不影响当前查询,所以我们可以离线处理,将查询以
r
r
r为标准,从小到大排序,每次查询前,假如当前
a
[
r
]
a[r]
a[r]及之前的未加入线段树,就先加入线段树,而a[r]也可以进行处理,既然相同数字只算一次,我们在读入的时候预设一个
l
a
s
t
last
last数组,用来储存每个数字上一次出现的位置
l
a
s
t
[
a
[
i
]
]
last[a[i]]
last[a[i]],这样的话,每次
a
[
i
]
a[i]
a[i]加入线段树的时候,其实只需要修改
[
l
a
s
t
[
a
[
i
]
+
1
,
i
]
[last[a[i]+1,i]
[last[a[i]+1,i]这一段就好了
那么查询和线段树的插入元素已经想好了,那么思考线段树的架构了。
既然我们的每个
a
[
i
]
a[i]
a[i]加入的时候只改变
[
l
a
s
t
[
a
[
i
]
+
1
,
i
]
[last[a[i]+1,i]
[last[a[i]+1,i],那我们可以构造线段树的当前sum为
[
l
,
r
]
[l,r]
[l,r]的和,其中l永远不变,r随当前查询更改,即每个节点维护以l为开头,以当前
q
u
e
r
y
query
query的
r
r
r为结尾的不含重复数字的
s
u
m
sum
sum,所以每次查询的时候直接查询
m
a
x
max
max就好,但这个
m
a
x
max
max应该是历史最大值,所以我们的线段树应该包含4个值,
s
u
m
sum
sum:当前
[
l
,
q
u
e
r
y
[
r
]
]
[l,query[r]]
[l,query[r]]的总和,
h
i
s
m
a
x
hismax
hismax:历史
[
l
,
q
u
e
r
y
[
r
]
]
[l,query[r]]
[l,query[r]]的最大总和,
s
u
m
sum
sum和
h
i
s
m
a
x
hismax
hismax各自需要一个
l
a
z
y
lazy
lazy标记来简化修改,具体可以见代码
这题数据是
−
1
e
5
1
e
5
-1e5~1e5
−1e5 1e5,所以用last数组来存储上一次出现的位置的时候,记得加上一个值,把
−
1
e
5
-1e5
−1e5调成非负数
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
ll a[maxn];
int pre[maxn];
int last[maxn];
int n,m;
struct Segment_Tree{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct node{
ll sum,hismax,sumlazy,hislazy;
node(){
sum=hismax=sumlazy=hislazy=0;
}
void init_lazy()
{
sumlazy=hislazy=0;
}
void init_all()
{
sum=hismax=sumlazy=hislazy=0;
}
node operator + (const node & b) const{
node ans;
ans.sum=max(sum,b.sum);
ans.hismax=max(hismax,b.hismax);
return ans;
}
node operator + (const ll & b) const{
node ans;
ans.sum=sum+b;
ans.hismax=max(hismax,ans.sum);
ans.sumlazy=sumlazy+b;
ans.hislazy=max(hislazy,ans.sumlazy);
return ans;
}
}t[maxn<<2];
void push_down(int p)
{
// cout<<p<<"\n";
t[ls(p)].hismax=max(t[ls(p)].hismax,t[ls(p)].sum+t[p].hislazy);
t[rs(p)].hismax=max(t[rs(p)].hismax,t[rs(p)].sum+t[p].hislazy);
t[ls(p)].sum+=t[p].sumlazy;
t[rs(p)].sum+=t[p].sumlazy;
t[ls(p)].hislazy=max(t[ls(p)].hislazy,\
t[ls(p)].sumlazy+t[p].hislazy);
t[rs(p)].hislazy=max(t[rs(p)].hislazy,\
t[rs(p)].sumlazy+t[p].hislazy);
t[ls(p)].sumlazy+=t[p].sumlazy;
t[rs(p)].sumlazy+=t[p].sumlazy;
t[p].init_lazy();
}
void push_up(int p)
{
t[p]=t[ls(p)]+t[rs(p)];
}
void change_add(int p,int l,int r,int ql,int qr,ll k)
{
if(ql<=l && r<=qr)
{
t[p]=t[p]+k;
return ;
}
push_down(p);
int mid=(l+r)>>1;
if(ql<=mid)
change_add(ls(p),l,mid,ql,qr,k);
if(mid<qr)
change_add(rs(p),mid+1,r,ql,qr,k);
push_up(p);
}
ll query_hismax(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
{
return t[p].hismax;
}
push_down(p);
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid)
ans=max(ans,query_hismax(ls(p),l,mid,ql,qr));
if(mid<qr)
ans=max(ans,query_hismax(rs(p),mid+1,r,ql,qr));
return ans;
}
#undef ls
#undef rs
}S1;
struct NODE{
int l,r,no;
bool operator < (const NODE & b) const{
return r<b.r;
}
}b[maxn];
ll c[maxn];
int main()
{
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
//-100000 ~~ 100000
pre[i]=last[a[i]+(int ) 1e5 +10];
last[a[i]+(int ) 1e5+10]=i;
}
cin>>m;
rep(i,1,m+1)
{
cin>>b[i].l>>b[i].r;
b[i].no=i;
}
sort(b+1,b+m+1);
int first=1;
rep(i,1,n+1)
{//按顺序进行添加
S1.change_add(1,1,n,pre[i]+1,i,a[i]);
for(;first<=m && b[first].r<=i;first++)
{
c[b[first].no]=S1.query_hismax(1,1,n,b[first].l,b[first].r);
}
}
rep(i,1,m+1)
{
cout<<c[i]<<"\n";
}
return 0;
}
GSS3 - Can you answer these queries III
这题做的挺尴尬的,可能是因为刚做完2,思路完全走2的思路,想着继续先离线,按r进行,将查询和修改分开操作,然后敲了200多行(逃),半成品在这,以后说不定可以改成完全?
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
// n 5e4
// a[i] -1e4~1e4
int a[maxn];
//究极离线操作
//查询按R从小到大排序
//每个节点维护的就是[l,query[r]]的值
//每次R往右边扩的时候,[1,r]全部加上a[r]
//修改 ai -> y
// 线段树的[1,i] + y-ai
struct Segment_Tree{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct node{
int sum;
int hismax;
int sumlazy;
int hislazy;
node()
{
sum=hismax=0;
sumlazy=hislazy=0;
}
void init_lazy()
{
sumlazy=hislazy=0;
}
void init_all()
{
sum=hismax=0;
sumlazy=hislazy=0;
}
node operator + (const node & b) const{
node ans;
ans.sum=max(sum,b.sum);
ans.hismax=max(hismax,b.hismax);
return ans;
}
node operator + (const ll & b)
{
node ans;
ans.sum=sum+b;
ans.hismax=max(hismax,ans.sum);
ans.sumlazy=sumlazy+b;
ans.hislazy=max(hislazy,ans.sumlazy);
return ans;
}
}t[maxn<<2];
void push_down(int p)
{
t[ls(p)].hismax=max(t[ls(p)].hismax,t[ls(p)].sum+t[p].hislazy);
t[rs(p)].hismax=max(t[rs(p)].hismax,t[rs(p)].sum+t[p].hislazy);
t[ls(p)].sum+=t[p].sumlazy;
t[rs(p)].sum+=t[p].sumlazy;
t[ls(p)].hislazy=max(t[ls(p)].hislazy,\
t[ls(p)].sumlazy+t[p].hislazy);
t[rs(p)].hislazy=max(t[rs(p)].hislazy,\
t[rs(p)].sumlazy+t[p].hislazy);
t[ls(p)].sumlazy+=t[p].sumlazy;
t[rs(p)].sumlazy+=t[p].sumlazy;
t[p].init_lazy();
}
void push_up(int p)
{
t[p]=t[ls(p)]+t[rs(p)];
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p].sum=t[p].hismax=a[l];
t[p].init_lazy();
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
void change(int p,int l,int r,int ql,int qr,int k)
{
if(ql<=l && r<=qr)
{
t[p]=t[p]+k;
return ;
}
push_down(p);
int mid=(l+r)>>1;
if(ql<=mid)
change(ls(p),l,mid,ql,qr,k);
if(mid<qr)
change(rs(p),mid+1,r,ql,qr,k);
push_up(p);
}
int query(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
{
return t[p].hismax;
}
push_down(p);
int mid=(l+r)>>1;
int ans=0;
if(ql<=mid)
ans=max(ans,query(ls(p),l,mid,ql,qr));
if(mid<qr)
ans=max(ans,query(rs(p),mid+1,r,ql,qr));
return ans;
}
#undef ls
#undef rs
}S1;
struct NODE{
int id,l,r;
// int id;
bool operator < (const NODE & b) const{
if(r==b.r)
return id<b.id;
return r<b.r;
}
}b[maxn],c[maxn],d[maxn];
int e[maxn];
//int d[maxn];
int n,m,qwe;
int main()
{
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
}
// S1.build(1,1,n);
cin>>m;
int m1,m2;
m1=m2=0;
rep(i,1,m+1)
{
// cin>>b[i].qwe>>b[i].l>>b[i].r;
cin>>qwe;
if(qwe)
{//query
b[++m1].id=i;
cin>>b[m1].l>>b[m1].r;
}
else
{
c[++m2].id=i;
cin>>c[m2].l>>c[m2].r;
}
}
sort(b+1,b+m1+1);
int cnt2=1;//标记修改数组跑到哪了
int first=1;//标记当前数组添加几个进入线段树了
rep(i,1,m1+1)
{
while(cnt2<=m2 && c[cnt2].id<b[i].id)
{
if(b[i].r<c[cnt2].l)
{//还没查询到这点呢,直接改就行
a[c[cnt2].l]=c[cnt2].r;
// cnt2++;
}
else
{//已经查询过了,那这个时候就得对之前的都做一次修改喽
S1.change(1,1,n,1,c[cnt2].l,c[cnt2].r-a[c[cnt2].l]);
a[c[i].l]=c[i].r;
//同时别忘了哦,记得修改a[c[cnt].l],方便后续继续修改
}
// S1.change(1,1,n,1,c[cnt2].l,c[cnt2].r-a[c[cnt2].l]);
// a[c[i].l]=c[i].r;
cnt2++;
}
while(first<=b[i].r)
{
}
d[i].id=i;
d[i].l=S1.query(1,1,n,b[i].l,b[i].r);
d[i].r=0;
// cout<<query(1,1,n,b[i].l,b[i].r)<<"\n";
}
sort(d+1,d+m1+1);
rep(i,1,m+1)
{
cout<<d[i].l<<"\n";
}
return 0;
}
但其实这题特别简单,就是把GSS1的代码加个修改,呜呜呜,代码如下(int就可,不用longlong)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
// n 5e4
// a[i] -1e4~1e4
#define int ll
int a[maxn];
int n,m,qwe,l,r,k;
struct Segment_Tree{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct node{
int sum,lmax,rmax,mx;
node()
{
sum=lmax=rmax=mx=0;
}
node operator + (const node & b ) const
{
node ans;
ans.sum=sum+b.sum;
ans.lmax=max(lmax,sum+b.lmax);
ans.rmax=max(b.rmax,rmax+b.sum);
// ans.mx=max(max(mx,b.mx),max(ans.lmax,ans.rmax));
ans.mx=max(max(mx,b.mx),rmax+b.lmax);
return ans;
}
}t[maxn<<2];
void push_up(int p)
{
t[p]=t[ls(p)]+t[rs(p)];
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p].sum=t[p].lmax=t[p].rmax=t[p].mx=a[l];
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
void change(int p,int l,int r,int ql,int k)
{
if(l==r)
{
t[p].sum=t[p].lmax=t[p].rmax=t[p].mx=k;
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)
change(ls(p),l,mid,ql,k);
if(mid<ql)
change(rs(p),mid+1,r,ql,k);
push_up(p);
}
node query(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
{
return t[p];
}
int mid=(l+r)>>1;
if(ql<=mid && mid<qr)
{
return query(ls(p),l,mid,ql,qr)+query(rs(p),mid+1,r,ql,qr);
}
else
if(ql<=mid)
{
return query(ls(p),l,mid,ql,qr);
}
else
{
return query(rs(p),mid+1,r,ql,qr);
}
}
}S1;
#undef int
int main()
{
iossync
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
}
S1.build(1,1,n);
cin>>m;
while(m--)
{
cin>>qwe;
switch(qwe)
{
case 0:{
cin>>l>>k;
S1.change(1,1,n,l,k);
break;
}
case 1:{
cin>>l>>r;
cout<<S1.query(1,1,n,l,r).mx<<"\n";
break;
}
}
}
return 0;
}
GSS4 - Can you answer these queries IV
这题只需要2个操作,求和是一样的,但更改操作跟以往完全不一样,是将区域内数字开方(向下取整)。
这题初看嘛,毫无思路,开方和,总之我想不到有什么简便算法可以一步把和转换成开方后的和。。。。
那这题似乎只有暴力修改一种途径了?每次将每个区域的元素重新计算吗?好像只能这样了,但注意到,我们每次是开方,而1的开方仍然是1,0也是,所以当一个数字到达1或0的时候,再进行开方操作已经毫无意义了,所以我们可以统计一个区域的max,假如当前max是1,就代表当前区域内数字不是1就是0了,开方已经毫无意义了,这个区域就不用操作了,而这题的每个元素最大只到1e18,最多开方6次,也已经到达1了,所以每个元素的最多操作次数仅为6,那么这题就做完了
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
ll a[maxn];
int n,m,qwe,l,r;
struct Segment_Tree{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct node{
ll mx;
// ll val;
ll sum;
node()
{
mx=sum=0;
}
}t[maxn<<2];
void push_up(int p)
{
t[p].mx=max(t[ls(p)].mx,t[rs(p)].mx);
t[p].sum=t[ls(p)].sum+t[rs(p)].sum;
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p].mx=t[p].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
void change(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr && t[p].mx<=1)
{
return ;
}
if(l==r)
{
// cout<<ceil(sqrt(t[p].sum))<<"\n";
t[p].mx=t[p].sum=floor(sqrt(t[p].sum));
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)
change(ls(p),l,mid,ql,qr);
if(mid<qr)
change(rs(p),mid+1,r,ql,qr);
push_up(p);
}
ll query(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
{
return t[p].sum;
}
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid)
ans+=query(ls(p),l,mid,ql,qr);
if(mid<qr)
ans+=query(rs(p),mid+1,r,ql,qr);
return ans;
}
#undef ls
#undef rs
}S1;
int main()
{
iossync;
int cnt=0;
while(cin>>n)
{
cout<<"Case #"<<++cnt<<":\n";
rep(i,1,n+1)
{
cin>>a[i];
}
S1.build(1,1,n);
cin>>m;
while(m--)
{
cin>>qwe>>l>>r;
if(l>r)
swap(l,r);
switch(qwe)
{
case 0:{
S1.change(1,1,n,l,r);
break;
}
case 1:{
cout<<S1.query(1,1,n,l,r)<<"\n";
break;
}
}
}
cout<<"\n";
}
return 0;
}
以及,这题在
l
u
o
g
u
luogu
luogu上有个重题,那题数据范围还比这题小,把
w
h
i
l
e
(
c
i
n
>
>
n
)
while(cin>>n)
while(cin>>n)和
c
a
s
e
case
case去掉后,就可以直接
a
c
ac
ac,嘿嘿嘿,白嫖一个蓝题,这是那题的链接
P4145 上帝造题的七分钟2 / 花神游历各国
GSS5 - Can you answer these queries V
从第五题开始,
l
u
o
g
u
luogu
luogu上就是紫题了(虽然我个人感觉2跟134压根不是一个难度),
这题就一个操作,查询,但这个查询就很有意思了,查询最大子段和,但左端点必须在
[
x
1
,
y
1
]
[x1,y1]
[x1,y1]之间,右端点必须在
[
x
2
,
y
2
]
[x2,y2]
[x2,y2]之间。
一眼看过去,woc,这固定了左右端点咋办嘛,可是仔细一想,啊?左右端点既然是有范围的,那么当
x
2
>
y
1
x2>y1
x2>y1的时候,中间的区域不就是必然取的吗,然后左边取rmax,右边取lmax,3者相加,不就是答案了吗,当
x
2
<
=
y
1
x2<=y1
x2<=y1的时候也就3种情况,把GSS1代码改改就ok了,但我一开始分类的有点多,这是我一开始的分类
while(m--)
{
cin>>x1>>y3>>x2>>y2;
if(y3+1<=x2-1)//不相交且中间有剩余
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax+S1.query(1,1,n,y3+1,x2-1).sum<<"\n";
else
if(y3+1==x2)
{//恰好不相交,中间无剩余
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax<<"\n";
}
else
if(x1==x2 && y3==y2)
{//完全重合
cout<<S1.query(1,1,n,x1,y3).mx<<"\n";
}
else
if(y3==x2)
{
if(x2!=y2)
{
ll ans=-inf;
ans=S1.query(1,1,n,x2,y3).mx;
ans=max(ans,S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2+1,y2).lmax);
if(x1<x2)
{
ans=max(ans,S1.query(1,1,n,x1,x2-1).rmax+S1.query(1,1,n,x2,y2).lmax);
}
cout<<ans<<"\n";
}
else
{
cout<<S1.query(1,1,n,x1,y3).rmax<<"\n";
}
}
else
{//部分重合
ll ans=-inf;
if(x1<x2)
ans=max(ans,S1.query(1,1,n,x1,x2-1).rmax+S1.query(1,1,n,x2,y2).lmax);
if(y3+1<=y2)
ans=max(ans,S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,y3+1,y2).lmax);
ans=max(ans,S1.query(1,1,n,x2,y3).mx);
cout<<ans<<"\n";
}
}
然后发现压根不用这么细,其实可以浓缩
while(m--)
{
cin>>x1>>y3>>x2>>y2;
if(y3<x2)
{
if(x2>=y3+2)
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax+S1.query(1,1,n,y3+1,x2-1).sum<<"\n";
else
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax<<"\n";
}
else
{
ll ans=-inf;
ans=S1.query(1,1,n,x2,y3).mx;
if(x2>=x1+1)
{
ans=max(ans,S1.query(1,1,n,x1,x2-1).rmax+S1.query(1,1,n,x2,y2).lmax);
}
if(y2>=y3+1)
{
ans=max(ans,S1.query(1,1,n,y3+1,y2).lmax+S1.query(1,1,n,x1,y3).rmax);
}
cout<<ans<<"\n";
}
}
所以这题就写完了,线段树部分甚至可以照搬之前的,也没change函数了,只需要query函数
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1e6+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
return b?gcd(b,a%b):a;
}
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
ll a[maxn];
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
ll n,m;
struct Segment_Tree{
struct node{
ll sum,mx;
ll lmax,rmax;
node(){
mx=lmax=rmax=sum=0;
}
void init(ll x=0)
{
mx=lmax=rmax=sum=x;
}
node operator + (const node & b) const
{
node ans;
ans.sum=sum+b.sum;
ans.lmax=max(lmax,sum+b.lmax);
ans.rmax=max(rmax+b.sum,b.rmax);
ans.mx=max(max(mx,b.mx),rmax+b.lmax);
return ans;
}
}t[maxn<<2];
void push_up(int p)
{
t[p]=t[ls(p)]+t[rs(p)];
}
void build(int p,int l,int r)
{
// t[p].init();
if(l==r)
{
t[p].init(a[l]);
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
node query(int p,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr)
return t[p];
int mid=(l+r)>>1;
if(ql<=mid && mid<qr)
{
return query(ls(p),l,mid,ql,qr)+query(rs(p),mid+1,r,ql,qr);
}
else
if(ql<=mid)
{
return query(ls(p),l,mid,ql,qr);
}
else
{
return query(rs(p),mid+1,r,ql,qr);
}
}
}S1;
int x1,y3,x2,y2,T;
int main()
{
iossync;
cin>>T;
while(T--)
{
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
}
S1.build(1,1,n);
cin>>m;
while(m--)
{
cin>>x1>>y3>>x2>>y2;
if(y3<x2)
{
if(x2>=y3+2)
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax+S1.query(1,1,n,y3+1,x2-1).sum<<"\n";
else
cout<<S1.query(1,1,n,x1,y3).rmax+S1.query(1,1,n,x2,y2).lmax<<"\n";
}
else
{
ll ans=-inf;
ans=S1.query(1,1,n,x2,y3).mx;
if(x2>=x1+1)
{
ans=max(ans,S1.query(1,1,n,x1,x2-1).rmax+S1.query(1,1,n,x2,y2).lmax);
}
if(y2>=y3+1)
{
ans=max(ans,S1.query(1,1,n,y3+1,y2).lmax+S1.query(1,1,n,x1,y3).rmax);
}
cout<<ans<<"\n";
}
}
}
return 0;
}