题解 漏网之鱼

传送门

调吐了
每次写线段树历史和都必定假至少一次

多次查询 \(\sum\limits_{i=l}^r\sum\limits_{j=i}^r \operatorname{mex}(a_i, a_{i+1},\cdots,a_{j})\)
考虑扫描线维护每个区间的 mex,最后历史和加起来
查询的话可以差分
发现删除一个数维护 mex 是较好维护的,所以扫描线枚举右端点
线段树中维护此时每个左端点到当前右端点形成的区间的 mex
\(a_i\) 上次出现的位置是 \(lst_i\)
那么删除这个右端点的贡献就是将 \([lst_i+1, i-1]\)\(a_i\) 取 min
将一次查询拆成扫到 \(l\)\(+\tt{query}(l, r)\),扫到 \(r+1\)\(-\tt{query(l, r)}\)

然后重点来了:这棵线段树怎么写呢?
发现 \(tim\)\(tag\) 是可以正常维护的
但这玩意能且仅能维护,也就是说加上除了 spread 之外的操作都麻烦的要死
对就是个废物
所以换一种扩展性较差的做法:
发现我们在每个时刻都对整棵线段树建立一次快照
所以每个点上的历史贡献是一个关于当前时间的一次函数 \(f(now)=k*now+b\)
这个系数就是当前这个节点的 sum
修改的话就是 \(k_2(now-lst)+k_1*lst+b\),拆开大力维护即可
注意在 upd 一个点之前要现将这个点的 tag 下放
注意因为这样只能对整棵树建快照所以处理完一个右端点后要将这个右端点置零
注意这个区间取 min 是可以直接写的,判断区间 \(max\) 是否 \(\leqslant dat\) 即可(在本题中均摊复杂度是对的)
注意我们只能对一个值完全相同的区间维护这样的操作,所以要开个域记录一个区间是否只有一个值,若不是要暴力递归
注意 \(\tt same\) 标记的上传它长这样

if (same(p<<1)&&same(p<<1|1)) same(p)=mx(p<<1)==mx(p<<1|1);
else same(p)=0;

而不长这样

same(p)=mx(p<<1)==mx(p<<1|1);

然后大概就没有什么了吧……
复杂度应该是 \(O((n+q)\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
// #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, 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, typ;
int a[N];

namespace task{
	ll ans[N];
	bool vis[N];
	set<int> s[N];
	int uni[N], mex[N], usiz, now;
	vector<pair<int, pair<int, int>>> add[N], del[N];
	bool same[N<<2];
	int tl[N<<2], tr[N<<2];
	ll sum[N<<2], len[N<<2], tag[N<<2], tagk[N<<2], tagb[N<<2], tk[N<<2], tb[N<<2], mx[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define sum(p) sum[p]
	#define len(p) len[p]
	#define tag(p) tag[p]
	#define tagk(p) tagk[p]
	#define tagb(p) tagb[p]
	#define tk(p) tk[p]
	#define tb(p) tb[p]
	#define same(p) same[p]
	#define mx(p) mx[p]
	inline void pushup(int p) {
		tk(p)=tk(p<<1)+tk(p<<1|1);
		tb(p)=tb(p<<1)+tb(p<<1|1);
		mx(p)=max(mx(p<<1), mx(p<<1|1));
		if (same(p<<1)&&same(p<<1|1)) same(p)=mx(p<<1)==mx(p<<1|1);
		else same(p)=0;
	}
	inline void spread(int p) {
		if (tag(p)==-1) return ;
		tk(p<<1)+=tagk(p)*len(p<<1); tb(p<<1)+=tagb(p)*len(p<<1);
		tk(p<<1|1)+=tagk(p)*len(p<<1|1); tb(p<<1|1)+=tagb(p)*len(p<<1|1);
		tagk(p<<1)+=tagk(p); tagb(p<<1)+=tagb(p);
		tagk(p<<1|1)+=tagk(p); tagb(p<<1|1)+=tagb(p);
		mx(p<<1)=tag(p<<1)=tag(p);
		mx(p<<1|1)=tag(p<<1|1)=tag(p);
		tag(p)=-1; tagk(p)=tagb(p)=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; len(p)=r-l+1; tag(p)=-1;
		if (l==r) {tk(p)=mx(p)=mex[l]; same(p)=1; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void upd(int p, int l, int r, ll dat) {
		// cout<<"upd: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<dat<<endl;
		spread(p);
		if (mx(p)<=dat) return ;
		if (l<=tl(p)&&r>=tr(p)&&same(p)) {
			tagk(p)=dat-mx(p); tagb(p)=-1ll*now*(dat-mx(p)); tag(p)=dat;
			tk(p)+=tagk(p)*len(p); tb(p)+=tagb(p)*len(p); mx(p)=tag(p);
			return ;
		}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, dat);
		if (r>mid) upd(p<<1|1, l, r, dat);
		pushup(p);
	}
	ll query(int p, int l, int r) {
		// cout<<"query: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<sum(p)<<' '<<val(p)<<' '<<tim(p)<<endl;
		if (l<=tl(p)&&r>=tr(p)) return tk(p)*now+tb(p);
		spread(p);
		int mid=(tl(p)+tr(p))>>1; ll ans=0;
		if (l<=mid) ans+=query(p<<1, l, r);
		if (r>mid) ans+=query(p<<1|1, l, r);
		return ans;
	}
	pair<ll, int> findr(int p, int l, int r, ll k) {
		if (tl(p)==tr(p)) return {mx(p), tl(p)};
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid&&r>mid) {
			pair<ll, int> ls=findr(p<<1, l, r, k);
			pair<ll, int> rs=findr(p<<1|1, l, r, k);
			return rs.fir>=k?rs:ls;
		}
		else if (l<=mid) return findr(p<<1, l, r, k);
		else return findr(p<<1|1, l, r, k);
	}
	namespace seg2{
		#undef ll 
		#define LL long long
		const int maxt=N<<2;
		LL tk[maxt],tb[maxt],tagk[maxt],tagb[maxt]; int mx[maxt],tag[maxt],sm[maxt],len[maxt];
		void upd(int x){
			tk[x]=tk[x<<1]+tk[x<<1^1];
			tb[x]=tb[x<<1]+tb[x<<1^1];
			mx[x]=max(mx[x<<1],mx[x<<1^1]);
			if (sm[x<<1]&&sm[x<<1^1]) sm[x]=mx[x<<1]==mx[x<<1^1];
			else sm[x]=0;
		}
		void maketree(int x,int l,int r){
			tag[x]=-1; len[x]=r-l+1;
			if (l==r) {
				tk[x]=mx[x]=mex[l],sm[x]=1;
				return;
			}
			int mid=(l+r)>>1;
			maketree(x<<1,l,mid),maketree(x<<1^1,mid+1,r);
			upd(x);
		}
		void downtag(int x,int l,int r){
			if (tag[x]==-1 || l>r) return ;
			tk[x<<1]+=tagk[x]*len[x<<1],tb[x<<1]+=tagb[x]*len[x<<1];
			tk[x<<1|1]+=tagk[x]*len[x<<1|1],tb[x<<1|1]+=tagb[x]*len[x<<1|1];
			tagk[x<<1]+=tagk[x],tagb[x<<1]+=tagb[x];
			tagk[x<<1^1]+=tagk[x],tagb[x<<1^1]+=tagb[x];
			tag[x<<1]=tag[x<<1^1]=tag[x];
			mx[x<<1]=mx[x<<1^1]=tag[x];
			tag[x]=-1,tagk[x]=tagb[x]=0;
		}
		void change(int x,int l,int r,int ll,int rr,int d){
			if (tag[x]!=-1) downtag(x,l,r);
			if (l>rr||r<ll||mx[x]<=d) return;
			if (ll<=l&&r<=rr&&sm[x]){
				tagk[x]=d-mx[x],tagb[x]=-1ll*now*(d-mx[x]),tag[x]=d;
				tk[x]+=tagk[x]*(r-l+1),tb[x]+=tagb[x]*(r-l+1),mx[x]=tag[x];
				return;
			}
			int mid=(l+r)>>1;
			change(x<<1,l,mid,ll,rr,d),change(x<<1^1,mid+1,r,ll,rr,d);
			upd(x);
		}
		LL find(int x,int l,int r,int ll,int rr){
			if (l>rr||r<ll) return 0;
			if (ll<=l&&r<=rr) return tk[x]*now+tb[x];
			if (tag[x]!=-1) downtag(x,l,r);
			int mid=(l+r)>>1;
			return find(x<<1,l,mid,ll,rr)+find(x<<1^1,mid+1,r,ll,rr);
		}
	}
	void solve() {
		for (int i=1,l,r; i<=m; ++i) {
			l=read(); r=read();
			add[l].pb({i, {l, r}}); del[r+1].pb({i, {l, r}});
		}
		for (int i=1; i<=n; ++i) uni[++usiz]=a[i];
		sort(uni+1, uni+usiz+1);
		usiz=unique(uni+1, uni+usiz+1)-uni-1;
		for (int i=1; i<=usiz; ++i) s[i].insert(0);
		for (int i=1; i<=n; ++i) s[a[i]=lower_bound(uni+1, uni+usiz+1, a[i])-uni].insert(i);
		// cout<<"a: "; for (int i=1; i<=n; ++i) cout<<a[i]<<' '; cout<<endl;
		int now=0;
		// cout<<"mex: ";
		for (int i=n; i; --i) {
			if (uni[a[i]]<=n+1) vis[uni[a[i]]]=1;
			while (vis[now]) ++now;
			mex[i]=now;
			// cout<<now<<' ';
		} //cout<<endl;
		build(1, 1, n);
		// seg2::maketree(1, 1, n);
		for (int i=n; i; --i) {
			++task::now;
			// cout<<"i: "<<i<<endl;
			// int l=*(--s[a[i]].lower_bound(i))+1, r=findr(1, 0, i-1, uni[a[i]]).sec;
			// cout<<"lr: "<<l<<' '<<r<<' '<<uni[a[i]]<<endl;
			// if (l<=r) upd(1, l, r, uni[a[i]]);
			int l=*(--s[a[i]].lower_bound(i))+1;
			// cout<<"l: "<<l<<' '<<i-1<<' '<<uni[a[i]]<<endl;
			if (l<i) upd(1, l, i-1, uni[a[i]]);
			// if (l<i) seg2::change(1, 1, n, l, i-1, uni[a[i]]);
			for (auto it:add[i]) ans[it.fir]+=query(1, it.sec.fir, it.sec.sec);
			for (auto it:del[i]) ans[it.fir]-=query(1, it.sec.fir, it.sec.sec);
			// for (auto it:add[i]) ans[it.fir]+=seg2::find(1, 1, n, it.sec.fir, it.sec.sec);
			// for (auto it:del[i]) ans[it.fir]-=seg2::find(1, 1, n, it.sec.fir, it.sec.sec);
			upd(1, i, i, 0);
			// seg2::change(1, 1, n, i, i, 0);
		}
		for (int i=1; i<=m; ++i) printf("%lld\n", ans[i]);
	}
}

signed main()
{
	freopen("escape.in", "r", stdin);
	freopen("escape.out", "w", stdout);

	typ=read(); n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	m=read();
	// force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-03-10 12:09  Administrator-09  阅读(2)  评论(0编辑  收藏  举报