题解 省选联考2020 B卷 幸运数字
Posted agonim
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 省选联考2020 B卷 幸运数字相关的知识,希望对你有一定的参考价值。
考虑将三种转化为统一形式。
- 对区间 ([L,R]) 做贡献;
- 对区间 ([A,A]) 做贡献;
- 对区间 ((-infty,B-1],[B+1,+infty)) 做贡献。
显然需要离散化后维护线段树。这里考虑最后答案可能的取值,即 ((L-1,L,R,R+1) (A-1,A,A+1) (B-1,B,B+1))。将其塞进离散化序列即可。
然后还要塞一下 ((-1e9,0,1e9)) 这三个点。比如当区间 ([-8,7]) 的优惠额度相等时,答案取 (0)(这东西很细节。
于是就变成裸的线段树了,包含区间修改和单点查询,写起来异常愉悦。由于异或一样满足结合律,即 (a operatorname{xor} (b operatorname{xor} c)= (a operatorname{xor} b) operatorname{xor} c),所以 (lazytag) 该怎么维护怎么维护……
(operatorname{Code:})
#include<bits/stdc++.h>
using namespace std;
inline int read() {
register int s=0,f=1;
register char ch=getchar();
while(!isdigit(ch)) {if(ch==‘-‘)f=-f; ch=getchar();}
while(isdigit(ch)) {s=(s<<1)+(s<<3)+(ch^48); ch=getchar();}
return s*f;
}
const int N=100005;
int n,t[N],L[N],R[N],A[N],B[N],w[N];
int raw[N<<2],f[N<<2],len,ans=-1e9; //离散化序列
vector <int> q;
struct node {
int l,r,sum,add;
} tree[N<<4];
void build(int x,int l,int r) { //建树
tree[x].l=l,tree[x].r=r;
tree[x].sum=tree[x].add=0;
if(l==r) return;
int mid=(tree[x].l+tree[x].r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void push_down(int x) { //下传标记
if(tree[x].add==0) return;
tree[x<<1].sum^=tree[x].add;
tree[x<<1|1].sum^=tree[x].add; //区间的 sum 作为过渡值,直到叶子节点
tree[x<<1].add^=tree[x].add;
tree[x<<1|1].add^=tree[x].add; //更新子节点标记
tree[x].add=0;
}
int ask(int x,int k) { //单点查询
if(k==tree[x].l && tree[x].r==k) return tree[x].sum;
push_down(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(k<=mid) return ask(x<<1,k);
if(k>mid) return ask(x<<1|1,k);
}
void change(int x,int l,int r,int d) { //区间修改
if(l<=tree[x].l && tree[x].r<=r) {
tree[x].sum=tree[x].sum^d;
tree[x].add=tree[x].add^d;
return;
}
push_down(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) change(x<<1,l,r,d);
if(r>mid) change(x<<1|1,l,r,d);
}
int main(){
n=read();
for(int i=1;i<=n;i++) {
t[i]=read();
if(t[i]==1) L[i]=read(),R[i]=read(),w[i]=read(),raw[++len]=L[i]-1,raw[++len]=L[i],raw[++len]=R[i]+1,raw[++len]=R[i];
if(t[i]==2) A[i]=read(),w[i]=read(),raw[++len]=A[i]-1,raw[++len]=A[i],raw[++len]=A[i]+1;
if(t[i]==3) B[i]=read(),w[i]=read(),raw[++len]=B[i]-1,raw[++len]=B[i],raw[++len]=B[i]+1; //构建离散化点
}
raw[++len]=0,raw[++len]=-1e9,raw[++len]=1e9;
sort(raw+1,raw+len+1);
len=unique(raw+1,raw+len+1)-raw-1; //去重
for(int i=1;i<=n;i++) {
if(t[i]==1) {
int pos1 = lower_bound(raw+1,raw+len+1,L[i])-raw;
int pos2 = lower_bound(raw+1,raw+len+1,R[i])-raw;
L[i]=pos1,R[i]=pos2;
}
if(t[i]==2) {
int pos = lower_bound(raw+1,raw+len+1,A[i])-raw;
A[i]=pos;
}
if(t[i]==3) {
int pos = lower_bound(raw+1,raw+len+1,B[i])-raw;
B[i]=pos;
}
}
build(1,1,len);
for(int i=1;i<=n;i++) {
if(t[i]==1) change(1,L[i],R[i],w[i]);
if(t[i]==2) change(1,A[i],A[i],w[i]); //单点修改转化区间修改
if(t[i]==3) change(1,1,B[i]-1,w[i]),change(1,B[i]+1,len,w[i]);
}
for(int i=1;i<=len;i++) f[i]=ask(1,i);
for(int i=1;i<=len;i++) if(f[i]>=ans) ans=f[i];
for(int i=1;i<=len;i++) if(f[i]==ans) q.push_back(i);
int mx=raw[q[0]];
for(int i=1;i<q.size();i++) {
if(abs(raw[q[i]])<abs(mx)) mx=raw[q[i]];
else if(abs(raw[q[i]])==abs(mx)) mx=max(mx,raw[q[i]]); //求最大额度
}
cout<<ans<<" "<<mx<<"
";
return 0;
}
以上是关于题解 省选联考2020 B卷 幸运数字的主要内容,如果未能解决你的问题,请参考以下文章
luoguP6623 [省选联考 2020 A 卷] 树(trie树)