B xor
题意
给定n个集合,编号为1-n,有m次询问,每次询问L,R,X,表示L-R的集合是否都能用子集异或和表示X
思路
学到了线性基的新操作,求两个基的交集。对于任意两个基来说,如果他们的交集构成的基,能够表示X,那么这两个基一定也能表示X。因此需要通过线段树来维护区间交集,剩下的就很简单了。之前在区间查询的时候有点智障的又求了一边交集,其实并不需要,在查询的时候直接find就能得到结果了。
C sequence
题意
求
m
a
x
1
≤
l
≤
r
≤
n
{
m
i
n
(
a
[
l
…
r
]
)
×
s
u
m
(
b
[
l
…
r
]
)
}
max_{1\le l\le r\le n}\{min(a [l…r] )×sum(b [l…r])\}
max1≤l≤r≤n{min(a[l…r])×sum(b[l…r])} 。
思路
首先通过单调队列或者单调栈可以求出a[i]作为最小值所影响的范围,再对b求前缀和以后用线段树维护最大和最小值。
假设L,R是a[i]作为最小值影响的区间,则有
当a[i]为正数时
a
n
s
=
m
a
x
(
a
[
i
]
∗
(
M
A
X
(
i
,
R
)
−
M
I
N
(
L
,
i
−
1
)
)
)
ans=max(a[i]*(MAX(i,R)-MIN(L,i-1)))
ans=max(a[i]∗(MAX(i,R)−MIN(L,i−1)))
当a[i]为负数时
a
n
s
=
m
a
x
(
a
[
i
]
∗
(
M
I
N
(
i
,
R
)
−
M
A
X
(
L
,
i
−
1
)
)
)
ans=max(a[i]*(MIN(i,R)-MAX(L,i-1)))
ans=max(a[i]∗(MIN(i,R)−MAX(L,i−1)))
具体看代码才能懂,这题真的是究极卡常数,T了无数发才过。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 3e6+10;
const int mod = 1e9+7;
const ll inf=1e18-1;
#define lson node<<1
#define rson node<<1|1
ll treemin[4*maxn]; // 线段树
ll treemax[4*maxn];
ll a[maxn],b[maxn];
int la[maxn];
int ra[maxn];
int n;
struct node{
ll v;
int pos;
}dque[maxn];
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
// 创建线段树
void build(int node,int l,int r){
if(l == r){
treemin[node]=b[l];
treemax[node]=b[l];
return;
}
int mid = (l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
treemin[node] = min(treemin[lson] , treemin[rson]);
treemax[node] = max(treemax[lson] , treemax[rson]);
}
// 区间查找
ll querymax(int node,int l,int r,int L,int R){
if(l >= L && r <= R)
{
return treemax[node];
}
int mid = (l+r) / 2;
ll sum;
sum = -inf;
if(mid >= L) sum= max(sum,querymax(lson,l,mid,L,R)) ;
if(mid < R) sum= max (sum,querymax(rson,mid+1,r,L,R));
return sum;
}
ll querymin(int node,int l,int r,int L,int R){
if(l >= L && r <= R)
{
return treemin[node];
}
int mid = (l+r) / 2;
ll sum;
sum = inf;
if(mid >= L) sum= min(sum,querymin(lson,l,mid,L,R)) ;
if(mid < R) sum= min(sum,querymin(rson,mid+1,r,L,R));
return sum;
}
void init()
{
int l=0,r=0;
dque[0].v=-inf;
a[n+1]=-inf;
for(int i=1;i<=n+1;i++)
{
while(a[i]<dque[r].v)
{
ra[dque[r--].pos]=i-1;
}
dque[++r].v=a[i];
dque[r].pos=i;
}
l=0,r=0;
dque[0].v=-inf;
a[0]=-inf;
for(int i=n;i>=0;i--)
{
while(a[i]<dque[r].v)
{
la[dque[r--].pos]=i+1;
}
dque[++r].v=a[i];
dque[r].pos=i;
}
build(1,0,n);
}
int main(){
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
}
for(int i=1;i<=n;i++)
{
b[i]=read();
b[i]+=b[i-1];
}
init();
ll ans=-inf;
for(int i=1;i<=n;i++)
{
int l=la[i];
int r=ra[i];
if(a[i]>0)
ans=max(ans,(querymax(1,0,n,i,r)-querymin(1,0,n,l-1,i-1))*a[i]);
else
ans=max(ans,(querymin(1,0,n,i,r)-querymax(1,0,n,l-1,i-1))*a[i]);
}
printf("%lld\n",ans);
return 0;
}