CF1148H Holy Diver
令 \(M_{l,r}=\text{mex}(a_l,a_{l+1},\cdots,a_{r})\)。可以发现有 \(M_{l,r}\ge M_{l+1,r}\) 和 \(M_{l,r}\ge M_{l,r-1}\),即一个集合的 \(\text{mex}\) 并不会比它的子集小。
假设第 \(r\) 行的第 \(l\) 个数为 \(M_{l,r},l\le r\)。
考虑每次往末尾插入一个数会发生什么,即现在由第 \(r\) 行转移到第 \(r+1\) 行。
首先,根据 \(\text{mex}\) 的定义有 \(M_{r+1,r+1}=[a_{r+1}=0]\),且第 \(r+1\) 行不会出现 \(a_{r+1}\)。
若原矩阵中没有过出现 \(a_{r+1}\),显然第 \(r+1\) 行的前 \(r\) 个数与第 \(r\) 行一样。
若出现了 \(a_{r+1}\),根据上面那个性质可以发现出现 \(a_{r+1}\) 的位置一定是一个区间,假设这个区间为 \([x,y]\),显然第 \(r+1\) 行只有 \([x,y]\) 上的数会发生改变。
然后考虑具体会变成什么,可以发现这只和某些数最后一次出现的位置有关。
因为 \([x,y]\) 中已经出现过 \(0,1,\cdots ,a_{r+1}\),因此只需要考虑 \(\ge a_{r+1}\) 的数。
然后从 \(a_{r+1}+1\) 开始依次考虑填什么,假设当前这个数为 \(A\),其最后一次出现位置为 \(p_A\),然后分类讨论:
-
若 \(p_A\ge y\),则显然这个 \(A\) 不会作为 \(\text{mex}\) 出现。
-
若 \(x\le p_A<y\),那么对于 \(\forall l\in(p_A,y]\),区间 \([l,r]\) 的 \(\text{mex}=A\),然后只需令 \(y← p_A\) ,转化成一个子问题。
-
若 \(p_A<x\),那么对于\(\forall l\in [x,y]\),区间 \([l,r]\) 的 \(\text{mex}\) 都会变成 \(A\),然后就结束了。
这样就得到了一个维护 \(M\) 矩阵的方法。
然后考虑如何处理询问,可以发现每次询问就是问一个矩阵的子矩阵中出现了多少次 \(k\)。
考虑对于一个数 \(k\) 在矩形出现的规律:
首先 \(k\) 的出现一定是将某个 \([x,y]\) 替换成 \(k\)。
由于 \(\text{mex}\) 的性质,从这一行开始,\(k\) 出现的位置一定是一个固定的区间 \([x_{k},y_{k}]\)。
若在之后没有加入 \(k\),这个区间并不会改变,因此 \(k\) 出现的位置为一个子矩阵。但是还有一种使区间变长的情况:\(k\) 右边的连续段被删除,其子段的最左边恰好等于 \(k\)。
然后若在某个时刻加入 \(k\),这一块 \(k\) 就会直接消失。要注意的是这只是这一块 \(k\) 消失,在右边 \(k\) 仍然可能会重新出现,但是原 \([x_k,y_k]\) 位置上的数均 \(>k\),而下一块 \(k\) 的左端点一定大于上一块的右端点。
因此 \(k\) 在整个 \(M\) 矩形中出现的位置为若干个连通块,而每个连通块由多个左端点相同的矩形构成。
然后将这些连通块排序,查找只需要二分找到两个界即可,然后通过预先维护面积的前缀和计算。
最后可以发现所有连通块的数量是 \(\mathcal O(n)\) 的。
证明考虑倒着分析,每次操作相当于将若干个连续端合并成一个,而初始状态和末状态的连续段数均为 \(\mathcal O(n)\),类似于珂朵莉树复杂度分析可知总共出现段数就是 \(\mathcal O(n)\) 的。
然后找到最小的 \(A\) 满足 \(p_A<y\) 是一个二维数点,弄棵主席树就行了
总时间复杂度 \(\mathcal O(n\log n)\)。
#include<bits/stdc++.h>
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
typedef long long ll;
int n;
ll la;
int a[222222];
struct sgt
{
int val[888888];
void modify(int p,int l,int r,int x,int k)
{
if(l==r)
{
val[x]=k;
return;
}
int mid=(l+r)>>1;
if(p<=mid) modify(p,l,mid,x<<1,k);
else modify(p,mid+1,r,x<<1|1,k);
val[x]=min(val[x<<1],val[x<<1|1]);
}
int query(int p,int l,int r,int x)
{
if(l==r) return l;
int mid=(l+r)>>1;
if(val[x<<1]<p) return query(p,l,mid,x<<1);
return query(p,mid+1,r,x<<1|1);
}
}st;
map<int,int>rt[222222];
int cnt,ls[28888888],rs[28888888];
ll val[28888888],lz[28888888];
struct node
{
int x,y,xx,yy;
inline int operator <(const node &A)const
{
return xx<A.xx;
}
};
struct Node
{
int x,y;
node v;
inline int operator <(const Node &A)const
{
return x<A.x;
}
};
set<node>s;
set<Node>vis[222222];
void modify(int L,int R,int l,int r,int &x,int lt,ll k)
{
x=++cnt;
ls[x]=ls[lt],rs[x]=rs[lt],val[x]=val[lt],lz[x]=lz[lt];
if(L<=l&&r<=R)
{
val[x]+=k*(r-l+1);
lz[x]+=k;
return;
}
int mid=(l+r)>>1;
if(L<=mid) modify(L,R,l,mid,ls[x],ls[lt],k);
if(mid<R) modify(L,R,mid+1,r,rs[x],rs[lt],k);
val[x]=val[ls[x]]+val[rs[x]];
}
ll query(int L,int R,int l,int r,int x)
{
if(L<=l&&r<=R) return val[x];
int mid=(l+r)>>1;
ll ret=lz[x]*(min(R,r)-max(l,L)+1);
if(L<=mid&&ls[x]) ret+=query(L,R,l,mid,ls[x]);
if(mid<R&&rs[x]) ret+=query(L,R,mid+1,r,rs[x]);
return ret;
}
inline void pop(node x,int k)
{
int t=x.xx;
s.erase(x);
if(x.yy!=k) vis[t].insert((Node){x.yy,k-1,x});
int lst=(rt[t].size()?rt[t].rbegin()->second:0);
int R;
modify(x.x,x.y,1,n,R,lst,k-x.yy);
if(rt[t].size()&&rt[t].rbegin()->first==k) rt[t].erase(prev(rt[t].end()));
rt[t][k]=R;
}
inline void push(node x,int k)
{
auto it=s.find(x);
if(it!=s.end()) x.x=(*it).x,pop(*it,k);
s.insert(x);
}
ll solve(int l,int r,int k)
{
ll ans=0;
if(rt[k].size())
{
auto it=rt[k].upper_bound(r);
if(it!=rt[k].begin())
{
--it;
ans+=query(l,r,1,n,(*it).second);
}
}
auto it=s.find((node){0,0,k,0});
if(it!=s.end()&&(*it).yy<=r) ans+=1ll*(r-(*it).yy+1)*(max(l-1,(*it).y)-max(l,(*it).x)+1);
else
{
auto itt=vis[k].upper_bound((Node){r,0,(node){0,0,0,0}});
if(itt==vis[k].begin()) return ans;
--itt;
if((*itt).y<r) return ans;
node t=(*itt).v;
ans+=1ll*(r-t.yy+1)*(max(l-1,t.y)-max(l,t.x)+1);
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n;
int x,l,r,k;
R(i,1,n)
{
cin>>x>>l>>r>>k;
x=(x+la)%(n+1),l=(l+la)%i+1,r=(r+la)%i+1,k=(k+la)%(n+1);
if(l>r) swap(l,r);
a[x]=i;
st.modify(x,0,n,1,i);
auto it=s.find((node){0,0,x,0});
if(it!=s.end())
{
int l=(*it).x,r=(*it).y;
pop(*it,i);
while(l<=r)
{
int t=st.query(r,0,n,1);
push((node){max(l,a[t]+1),r,t,i},i);
r=a[t];
}
}
push((node){i,i,!x,i},i);
cout<<(la=solve(l,r,k))<<'\n';
}
}

浙公网安备 33010602011771号