CF1148H Holy Diver

  • 链接: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;
}
posted @ 2021-03-30 20:09  y_dove  阅读(237)  评论(0编辑  收藏  举报