- 链接:CF1148H Holy Diver
- 题意简述:看链接
- 参考了杜爷爷的题解
-
solution
- 我们首先考虑\(mex_{i = l}^{r}a_i\)怎么算,考虑扫描线,从左往右扫,假设当前的数为\(v\),显然只会对\(mex\)为\(v\)的产生影响
- 我们考虑当前\(mex\)为\(v\)的区间是\([l,r]\),我们考虑向前二分找到第一个\(v+1\),并把它前面的\(mex\)都改为\(v+1\),并继续向后找到第一个\(v+2\),这种做法看似十分暴力,其实均摊下来段数是\(O(n)\)的(每个数最多改变一次段)
- 紧接着问题便成为了\([l,r]\)内,每个\(mex\)值,这里假设为\(k\),会出现一段时间(从第一次被修改成\(k\),到修改成不是\(k\),注意\(mex\)值随着扫描线向右单调增),求它们出现的时间和.
- 于是我们考虑维护对每个\(k\),维护它们出现的时间和,以及数量和,前者可以用费用提前计算的思想计算已经不是\(k\)的数存在的时间,后者可以用当前询问的时间来计算仍然是\(k\)的数乘以时间的和.
- 可以用扫描线,但这题强制在线,考虑用可持久化线段树来维护,用\(set\)维护各个时间点的根,用标记可持久化来支持区间修改
/*CF1148H Holy Diver*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int read(){
char c = getchar();
int x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
struct pii{
int fi,se;
pii (int _a = 0,int _b = 0){
fi = _a,se = _b;
}
bool operator <(const pii &A)const{
return fi < A.fi;
}
bool operator <=(const pii &A)const{
return fi <= A.fi;
}
};
typedef pii mp;
const int _ = 2e5 + 7;int n;
#define pb push_back
set<pii>Rt[_];
typedef set<pii>::iterator IT;
vector<int>exi[_];
struct SegmentTree{
int lc,rc;
ll add1,add2;
ll s1,s2;
}t[_*128];int cnt = 0;
int modify(int now,int l,int r,int a,int b,ll v1,ll v2){
int p = ++cnt;
t[p] = t[now];
t[p].s1 += (min(r,b) - max(a,l) + 1) * v1;
t[p].s2 += (min(r,b) - max(a,l) + 1) * v2;
if(a <= l && b >= r){/*如果不下传了*/
t[p].add1 += v1;
t[p].add2 += v2;
return p;
}
int mid = (l + r) >> 1;
if(a <= mid) t[p].lc = modify(t[now].lc,l,mid,a,b,v1,v2);
if(b > mid) t[p].rc = modify(t[now].rc,mid+1,r,a,b,v1,v2);
return p;
}
ll query(int p,int l,int r,int a,int b,const int T){
/*if(a == 5 && b == 11){
cout<<"hxsb"<<"!!!"<<' '<<p<<' '<<l<<' '<<r<<endl;
}*/
if(!p || a > b) return 0;
if(a <= l && b >= r){
return T * t[p].s1 + t[p].s2;
}
int mid = (l + r) >> 1;
int len = min(r,b) - max(a,l) + 1;
ll ans = T * t[p].add1 * len + t[p].add2 * len;
if(a <= mid) ans += query(t[p].lc,l,mid,a,b,T);
if(b > mid) ans += query(t[p].rc,mid+1,r,a,b,T);
return ans;
}
void Add(int k,int l,int r,int T){/*在T时刻,[l,r]mex = k的段出现了*/
if(l > r) return;
// if(k == 1) cout<<l<<' '<<r<<' '<<T<<"!!!"<<endl;
IT it = Rt[k].end();it--;int lst = (*it).se;
int rt = modify(lst,1,n,l,r,1,-T+1);
if((*it).fi == T) Rt[k].erase(it);
Rt[k].insert(mp(T,rt));
}
void Dec(int k,int l,int r,int T){/*在T时刻,[l,r]mex = k的段消失了*/
if(l > r) return;
/*if(k == 1)
cout<<T<<' '<<l<<' '<<r<<endl;*/
IT it = Rt[k].end();it--;int lst = (*it).se;
int rt = modify(lst,1,n,l,r,-1,T-1);
if((*it).fi == T) Rt[k].erase(it);
Rt[k].insert(mp(T,rt));
}
pii E[_];
void solve(int v,int T){
int l = E[v].fi,r = E[v].se;
if(l > r) return;
int P = r;int val = v + 1;
Dec(v,l,r,T);E[v].fi = 0,E[v].se = -1;
// if(T == 7) cout<<v<<' '<<l<<' '<<r<<endl;
while(1){
int p = 0;int L = 0,R = exi[val].size() - 1;
while(L <= R){
int Mid = (L + R) >> 1;
if(exi[val][Mid] <= T){
p = exi[val][Mid];
L = Mid + 1;
}
else R = Mid - 1;
}
if(p < l){
Add(val,l,P,T);
if(E[val].se == l - 1){
E[val].se = P;
}
else E[val] = mp(l,P);
break;
}
Add(val,p+1,P,T);
if(p + 1 <= P) E[val] = mp(p+1,P);
P = min(P,p);val++;
}
}
ll query(int k,int l,int r){
int T = r;
if(Rt[k].size() == 1) return 0;
IT it = Rt[k].upper_bound(mp(r,0));
it--;
int rt = (*it).se;
// cout<<rt<<' '<<l<<' '<<r<<' '<<T<<endl;
return query(rt,1,n,l,r,T);
}
int main(){
n = read();
ll ans = 0;
for(int i = 0; i <= n + 1; ++i) E[i] = mp(0,-1);
for(int i = 0; i <= n + 1; ++i) Rt[i].insert(mp(0,0));
for(int i = 1; i <= n; ++i){
ll a = read(),l = read(),r = read(),k = read();
a = (a + ans) % (n + 1);
l = (l + ans) % i + 1;r = (r + ans) % i + 1;
if(l > r) swap(l,r);
k = (k + ans) % (n + 1);
// cout<<a<<' '<<l<<' '<<r<<' '<<k<<' '<<i<<"!!!"<<endl;
exi[a].pb(i);
solve(a,i);
// if(i == 7) cout<<query(3,3,7)<<endl;
// if(i == 7) cout<<E[3].fi<<' '<<E[3].se<<endl;
if(a == 0){
if(E[1].se == i - 1) E[1].se++;
else E[1] = mp(i,i);
Add(1,i,i,i);
}
else{
if(E[0].se == i - 1) E[0].se++;
else E[0] = mp(i,i);
Add(0,i,i,i);
}
ans = query(k,l,r);
printf("%lld",ans);putchar('\n');
}
return 0;
}