題解 省選聯考2020 B卷 幸運數字
阿新 • • 發佈:2020-07-24
考慮將三種轉化為統一形式。
- 對區間 \([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\)
\(\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<<"\n"; return 0; }