题解 Cicada 拿衣服
- 见到这些奇奇怪怪的题是不是应该试着证下状态数上界啊
首先观察题目里给的柿子,可以发现 \(or-and\) 单调增, \(min-max\) 单调减
神仙思路,发现对于一个给定的左端点,我怀疑出题人是左撇子,不同的 \(or-and\) 最多只有 \(2logn\) 个,证明应该很简单
那尝试把这些 \(or-and\) 相同的区间拎出来,从右向左枚举区间,在区间内二分可得合法的最远右端点
然后问题来了:如何 \(O(1)\) 维护出这些区间
神仙思路,考虑什么是这些区间的边界,会发现一个数是边界当且仅当这一位上出现了之前没有在这一位上出现过的数
也即比如左边界上第 \(i\) 位是1,那向右找到第一个这一位上是0的数,那个数就会是一个边界
这个可以维护出一个next0和一个next1单调指针,每次排个序处理
然后区间最值,区间与或都需要 \(O(1)\) 出,都可以用ST表
-
所以满足区间可重性的东西都可以用ST表?
-
关于区间整体取max:
另一种实现方法是把线段差分,拆分为在 \(l\) 插入一个长度,在 \(r\) 删除一个长度的事件,拿一个multiset
维护,每次取出最大值即可
但这样要求区间数不能太多 -
关于ST表和lca的fa数组:
把大小是log的那一维放在前面真的会快
然后具体实现上注意我让每个端点是区间的右端点,所以每次还得特别把位置 \(n\) 扔进去
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
#define max2(a, b) ((a)>(b)?(a):(b))
#define min2(a, b) ((a)<(b)?(a):(b))
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans;
}
int n, k;
int ta1[28][N], ta2[28][N], ta3[28][N], ta4[28][N], top, lg[N], a[N];
pair<int, int> add[N], del[N];
multiset<int> s;
struct point{
int dlt, pos0, pos1;
point():pos0(1),pos1(1){}
int nxt0(int i) {
//cout<<"nxt0: "<<i<<' '<<pos0<<endl;
if (i>=pos0) {pos0=i+1; i=1<<dlt; while (pos0<=n && (a[pos0]&i)) ++pos0;}
//cout<<"return "<<pos0<<endl;
return pos0;
}
int nxt1(int i) {
if (i>=pos1) {pos1=i+1; i=1<<dlt; while (pos1<=n && !(a[pos1]&i)) ++pos1;}
return pos1;
}
}p[28];
inline int qmin(int l, int r) {
int t=lg[r-l+1]-1;
return min(ta2[t][l], ta2[t][r-(1<<t)+1]);
}
inline int qmax(int l, int r) {
int t=lg[r-l+1]-1;
return max(ta1[t][l], ta1[t][r-(1<<t)+1]);
}
inline int qor(int l, int r) {
int t=lg[r-l+1]-1;
return ta3[t][l]|ta3[t][r-(1<<t)+1];
}
inline int qand(int l, int r) {
int t=lg[r-l+1]-1;
return ta4[t][l]&ta4[t][r-(1<<t)+1];
}
signed main()
{
n=read(); k=read();
for (reg i=1; i<=n; ++i) a[i]=read();
for (reg i=1; i<=n; ++i) ta1[0][i]=ta2[0][i]=ta3[0][i]=ta4[0][i]=a[i];
for (reg i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
int lim=lg[n]-1;
for (reg j=0; j<lim; ++j)
for (reg i=1,t,lm=n-(1<<(j+1))+1; i<=lm; ++i) {
t=i+(1<<j);
ta1[j+1][i]=max2(ta1[j][i], ta1[j][t]);
ta2[j+1][i]=min2(ta2[j][i], ta2[j][t]);
ta3[j+1][i]=ta3[j][i]|ta3[j][t];
ta4[j+1][i]=ta4[j][i]&ta4[j][t];
}
for (reg i=0; i<27; ++i) p[i].dlt=i;
int tem[30];
for (reg i=1; i<=n; ++i) {
//cout<<"i="<<i<<": "<<endl;
for (reg j=0; j<27; ++j) tem[j]=(a[i]&(1<<j))?p[j].nxt0(i):p[j].nxt1(i);
tem[27]=i; tem[28]=n+1;
sort(tem, tem+29);
//assert(tem[0]==i);
//cout<<"tem: "; for (int i=0; i<=27; ++i) cout<<tem[i]<<' '; cout<<endl;
for (reg j=28,t1,t2,l,r,mid; j; --j) {
if (tem[j-1]==tem[j]) continue;
t1=qor(i, tem[j]-1)-qand(i, tem[j]-1), t2=qmin(i, tem[j-1])-qmax(i, tem[j-1]);
if (t1+t2>=k) {
//cout<<"t1="<<t1<<" and t2="<<t2<<' '<<t1+t2<<endl;
//cout<<"tem_j: "<<tem[j-1]<<' '<<tem[j]-1<<endl;
l=tem[j-1], r=tem[j]-1;
while (l<=r) {
mid=(l+r)>>1;
if (t1+qmin(i, mid)-qmax(i, mid)>=k) l=mid+1;
else r=mid-1;
}
//cout<<"lr: "<<l<<' '<<r<<endl;
add[++top]=make(i, l-i), del[top]=make(l, l-i);
break;
}
}
}
sort(del+1, del+top+1);
int pos1=1, pos2=1;
//cout<<"---add---"<<endl; for (int i=1; i<=top; ++i) cout<<add[i].fir<<','<<add[i].sec<<endl;
//cout<<"---del---"<<endl; for (int i=1; i<=top; ++i) cout<<del[i].fir<<','<<del[i].sec<<endl;
for (reg i=1; i<=n; ++i) {
//cout<<"add: "<<add[i].sec<<endl;
while (pos1<=top && add[pos1].fir<=i) s.insert(add[pos1++].sec);
while (pos2<=top && del[pos2].fir<=i) {
//cout<<"del: "<<del[pos].fir<<' '<<del[pos].sec<<endl;
s.erase(s.find(del[pos2++].sec));
}
printf("%d ", s.size()?*s.rbegin():-1);
}
printf("\n");
return 0;
}