题解 玫瑰花精
此题高度恶心,极其卡细节,最后研究题解一个多小时才写对,值得什么时候再复做一下以自虐
这题貌似优先队列也可以做,
二元组维护空区间,再维护两个数组记录每个位置所对应的(如果有)向左和向右的两个二元组编号
开个bool数组作为失效标记就好了
先留坑,有空回来写
说下正解写法吧
\(l,r\)什么的一概初始化成0其实就可以
随时注意是左边的优于右边的,也就是说夹在左右区间中间的那部分其实优于右区间的部分(我大脑短路调了一下午重构了4次居然没发现这个问题)
还有需要特判区间1的\(l=0\)的情况,它所对应的貌似是在一个空区间内放花精
对\(l-1, n-r, mid\)的比较实质上是对最左边花精左边,最右边花精右边,中间花精之间的比较,
所以要特判只有一个花精,没有中间这部分空间的情况
这题极适合练判边界什么的用,优先队列的思路有空也可以写写
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000100
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
namespace force{
int tab[N], a[N];
bool vis[N];
void solve() {
for (int i=1,f,x; i<=m; ++i) {
f=read(); x=read();
if (f&1) {
memset(a, 0, sizeof(int)*1010);
a[0]=a[n+1]=INF;
for (int i=1; i<=n; ++i)
if (vis[i]) a[i]=0;
else a[i]=a[i-1]>n?a[i-1]-1:a[i-1]+1;
for (int i=n,cnt=INF; i; --i)
if (vis[i]) cnt=0;
else a[i]=min(a[i], a[i+1]+1);
//cout<<"a: "; for (int i=1; i<=n; ++i) cout<<a[i]<<' '; cout<<endl;
//cout<<"vis: "; for (int i=1; i<=n; ++i) cout<<vis[i]<<' '; cout<<endl;
int maxn=0, maxi;
for (int i=1; i<=n; ++i) if (!vis[i] && a[i]>maxn) maxn=a[i], maxi=i;
vis[maxi]=1;
tab[x]=maxi;
printf("%d\n", maxi);
}
else vis[tab[x]]=0;
}
}
}
namespace task{
const int SIZE=N<<2;
int tab[1000010];
int tl[SIZE], tr[SIZE], lran[SIZE], rran[SIZE], len[SIZE], pos[SIZE], cnt[SIZE];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define l(p) lran[p]
#define r(p) rran[p]
#define len(p) len[p]
#define pos(p) pos[p]
#define cnt(p) cnt[p]
void pushup(int p) {
//cout<<"pushup "<<p<<' '<<tl(p)<<' '<<tr(p)<<endl;
cnt(p)=cnt(p<<1)+cnt(p<<1|1);
//cout<<"cnt: "<<cnt(p)<<endl;
//l(p)=min(l(p<<1), l(p<<1|1));
//r(p)=max(r(p<<1), r(p<<1|1));
l(p)=l(p<<1)?l(p<<1):l(p<<1|1);
r(p)=r(p<<1|1)?r(p<<1|1):r(p<<1);
//if (cnt(p)<=1) {len(p)=pos(p)=0; return ;}
if (len(p<<1)>=len(p<<1|1)) len(p)=len(p<<1), pos(p)=pos(p<<1);
else len(p)=len(p<<1|1), pos(p)=pos(p<<1|1);
if (l(p<<1|1)<=n && r(p<<1) && (l(p<<1|1)-r(p<<1))/2>=len(p<<1|1) && (l(p<<1|1)-r(p<<1))/2>len(p<<1)) len(p)=(l(p<<1|1)-r(p<<1))/2, pos(p)=(r(p<<1)+l(p<<1|1))>>1;
}
void build(int p, int l, int r) {
//cout<<"build "<<p<<' '<<l<<' '<<r<<endl;
tl(p)=l; tr(p)=r; l(p)=0; r(p)=0;
//cout<<"len: "<<p<<' '<<len(p)<<endl;
//cout<<"build-pos: "<<p<<' '<<pos(p)<<endl;
if (l>=r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int pos2) {
//cout<<"upd "<<p<<' '<<pos2<<endl;
if (!l(p)||pos2<l(p)) l(p)=pos2;
if (!r(p)||pos2>r(p)) r(p)=pos2;
if (tl(p)==tr(p)) {cnt(p)=1; l(p)=r(p)=tr(p); len(p)=0; pos(p)=0; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos2<=mid) upd(p<<1, pos2);
else upd(p<<1|1, pos2);
pushup(p);
}
int query() {
if (!l(1)) {upd(1, 1); return 1;}
//cout<<"query "<<l(1)<<' '<<r(1)<<' '<<len(1)<<' '<<pos(1)<<endl;
int maxn, maxi;
maxn = max(max(l(1)-1, n-r(1)), len(1));
//cout<<"query cmp "<<l(1)-1<<' '<<n-r(1)<<' '<<len(1)<<endl;
if (maxn==l(1)-1) {upd(1, 1); return 1;}
else if (maxn==len(1)) {
int ans=pos(1);
//cout<<"ans: "<<pos(1)<<endl;
upd(1, ans);
return ans;
}
else {upd(1, n); return n;}
}
void remove(int p, int pos2) {
assert(pos2);
//cout<<"remove "<<p<<' '<<pos2<<endl;
if (tl(p)==tr(p)) {l(p)=0; r(p)=0; len(p)=pos(p)=cnt(p)=0; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos2<=mid) remove(p<<1, pos2);
else remove(p<<1|1, pos2);
pushup(p);
}
void solve() {
//memset(lran, 127, sizeof(lran));
build(1, 1, n);
for (int i=1,f,x; i<=m; ++i) {
f=read(); x=read();
if (f&1) printf("%d\n", tab[x]=query()); //, cout<<endl;
else remove(1, tab[x]), tab[x]=0;
}
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); m=read();
task::solve();
return 0;
}