题解 底垫

传送门

  • 给定 \(n\) 个区间和 \(m\) 个询问,每次求编号在 \([l[i], r[i]]\) 内区间并的长度,支持离线
    把询问离线,按右端点升序排序
    可以在值域轴上用set维护连续段,按连续段的左端点排序,同时存储这个连续段最晚的那次被覆盖的时间
    每次新加入一段区间时,删掉它覆盖的连续段,并加入它自己即可。每次新加一段区间最多会使连续段个数增加2,所以这部分维护是 \(O(nlogn)\)
    然后再在区间的编号轴上维护一个后缀和树状数组
    假设我们在插入第 \(i\) 个区间时把一段长度为 \(k\) 的、最晚被覆盖时间为 \(t\) 的连续段删掉了,利用差分思想,我们在时刻 \(t\) 加上一个 \(-k\),在时刻 \(i\) 加上一个 \(k\)
    然后如果有询问的右端点为 \(i\),在树状数组上查询后缀和就行了
  • 树状数组维护后缀和:其实把修改和查询反一下就行了
    upd: for (; i; i-=i&-i)
    query: for (; i<=n; i+=i&-i)

于是考虑怎么统计期望
可以先算出子区间总和,然后除以区间数
仍然考虑删掉连续段时对答案的贡献。如果最终询问的 \(l \in [t+1, i]\) ,那么贡献为 \((i-l+1)(r-i+1)k\),否则贡献为 \((i-t)(r-i+1)k\)
于是把柿子拆开,维护系数即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
#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;
int l[N], r[N], a[N], b[N];
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {a%=mod; ll ans=1ll; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	int top;
	const ll inv2=500000004;
	struct line{int l, r; inline void build(int a, int b) {l=a; r=b;}}p[N];
	inline bool operator < (line a, line b) {return a.l==b.l?a.r<b.r:a.l<b.l;}
	inline ll qsum(ll t) {t%=mod; return t*(t+1)%mod*inv2%mod;}
	void solve() {
		// cout<<"inv2: "<<qpow(2, mod-2)<<endl;
		for (int i=1; i<=m; ++i) {
			ll inv=qpow(qsum(b[i]-a[i]+1), mod-2), ans=0;
			// cout<<"qsum: "<<qsum(b[i]-a[i]+1)<<endl;
			for (reg c=a[i]; c<=b[i]; ++c) {
				for (reg d=c; d<=b[i]; ++d) {
					top=0;
					for (reg j=c; j<=d; ++j) p[++top].build(l[j], r[j]);
					sort(p+1, p+top+1);
					ll sum=0; int tl=p[1].l, tr=p[1].r;
					for (reg k=2; k<=top; ++k) {
						if (p[k].l>tr) {sum+=tr-tl+1; tl=p[k].l; tr=p[k].r;}
						else tr=max(tr, p[k].r);
					}
					sum+=tr-tl+1;
					// cout<<"sum: "<<c<<' '<<d<<' '<<sum<<endl;
					ans=(ans+sum%mod*inv)%mod;
				}
			}
			printf("%lld\n", ans);
		}
	}
}

namespace task{
	struct line{mutable int l, r, t; line(){} line(int a, int b, int c):l(a),r(b),t(c){}};
	inline bool operator < (line a, line b) {return a.l==b.l?a.r<b.r:a.l<b.l;}
	set<line> s;
	ll binl[N], binr[N], binlr[N], binc[N], ans[N];
	const ll inv2=500000004;
	struct que{int l, r, rk; inline void build(int a, int b, int c) {l=a; r=b; rk=c;}}q[N];
	inline bool operator < (que a, que b) {return a.r<b.r;}
	inline void upd(ll* a, int i, ll dat) {dat%=mod; for (; i; i-=i&-i) a[i]=(a[i]+dat)%mod;}
	inline ll query(ll* a, int i) {ll ans=0ll; for (; i<=n; i+=i&-i) ans=(ans+a[i])%mod; return ans;}
	inline ll qsum(ll t) {t%=mod; return t*(t+1)%mod*inv2%mod;}
	void solve() {
        for (int i=1; i<=m; ++i) q[i].build(a[i], b[i], i);
		sort(q+1, q+m+1);
		s.insert(line(1, 2e9, 0));
		int pos=1;
		for (int i=1,t; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			// cout<<"set: "; for (auto it:s) cout<<it.l<<','<<it.r<<','<<it.t<<"  "; cout<<endl;
			auto it=s.lower_bound(line(l[i], 0, 0));
			// if (it==s.end()) cout<<"end"<<endl;
			// cout<<"it: "<<it->l<<' '<<it->r<<endl;
			// cout<<2<<endl;
			if (it==s.end()) {
				// cout<<"pos1: "<<endl;
				auto it=s.rbegin();
				// cout<<"rit: "<<it->l<<','<<it->r<<','<<it->t<<endl;
				assert(it!=s.rend());
				if (it->r>=l[i]) {
					// cout<<"rit2: "<<it->l<<','<<it->r<<','<<it->t<<endl;
					t=it->t;
					int k=min(it->r, r[i])-l[i]+1;
					upd(binr, i, k*(i+1));
					upd(binl, i, k*(i-1));
					upd(binlr, i, -k);
					upd(binc, i, k*(-i*i%mod+1));
					if (t) {
						upd(binr, t, k*(-(i+1)));
						upd(binl, t, k*(-(i-1)));
						upd(binlr, t, k);
						upd(binc, t, k*(i*i%mod-1));
						upd(binr, t, k*(i-t));
						upd(binc, t, (-i*i%mod+i*t%mod+i-t)%mod*k%mod);
					}
					// cout<<"rit3: "<<it->l<<','<<it->r<<','<<it->t<<endl;
					int tem=it->r;
					it->r=l[i]-1;
					if (it->l>it->r) s.erase(s.find(*it));
					if (tem > r[i]) s.insert(line(r[i]+1, tem, t)); //, cout<<"ins: "<<r[i]+1<<' '<<it->r<<' '<<t<<endl;
					s.insert(line(l[i], r[i], i));
				}
			}
			else {
				// cout<<"pos2"<<endl;
				if (it!=s.begin()) {
					// cout<<"case1"<<endl;
					--it;
					if (it->r>=l[i]) {
						t=it->t;
						int k=min(it->r, r[i])-l[i]+1;
						upd(binr, i, k*(i+1));
						upd(binl, i, k*(i-1));
						upd(binlr, i, -k);
						upd(binc, i, k*(-i*i%mod+1));
						if (t) {
							upd(binr, t, k*(-(i+1)));
							upd(binl, t, k*(-(i-1)));
							upd(binlr, t, k);
							upd(binc, t, k*(i*i%mod-1));
							upd(binr, t, k*(i-t));
							upd(binc, t, (-i*i%mod+i*t%mod+i-t)%mod*k%mod);
						}
						int tem=it->r;
						it->r=l[i]-1;
						if (it->l>it->r) s.erase(s.find(*it));
						if (tem > r[i]) s.insert(line(r[i]+1, tem, t));
					}
					it=s.lower_bound(line(l[i], 0, 0));
				}
				// cout<<"pos3: "; for (auto it:s) cout<<it.l<<','<<it.r<<','<<it.t<<"  "; cout<<endl;
				it=s.lower_bound(line(l[i], 0, 0));
				// cout<<"check: "<<it->l<<','<<it->r<<','<<it->t<<endl;
				for (; it!=s.end() && it->l>=l[i] && it->l<=r[i]; it=s.lower_bound(line(l[i], 0, 0))) {
					t=it->t;
					// cout<<"it: "<<it->l<<','<<it->r<<','<<it->t<<endl;
					int k=min(r[i], it->r)-it->l+1;
					upd(binr, i, k*(i+1));
					upd(binl, i, k*(i-1));
					upd(binlr, i, -k);
					upd(binc, i, k*(-i*i%mod+1));
					if (t) {
						upd(binr, t, k*(-(i+1)));
						upd(binl, t, k*(-(i-1)));
						upd(binlr, t, k);
						upd(binc, t, k*(i*i%mod-1));
						upd(binr, t, k*(i-t));
						upd(binc, t, (-i*i%mod+i*t%mod+i-t)%mod*k%mod);
					}
					int tem=it->r;
					s.erase(it);
					if (tem > r[i]) s.insert(line(r[i]+1, tem, t)); //, cout<<"add: "<<r[i]+1<<endl;
				}
				s.insert(line(l[i], r[i], i));
			}
			for (; pos<=m && q[pos].r==i; ++pos) {
				ans[q[pos].rk] = (q[pos].l*query(binl, q[pos].l)%mod + q[pos].r*query(binr, q[pos].l)%mod + q[pos].l*q[pos].r%mod*query(binlr, q[pos].l)%mod + query(binc, q[pos].l))%mod;
				ans[q[pos].rk] = ans[q[pos].rk]*qpow(qsum(q[pos].r-q[pos].l+1), mod-2)%mod;
			}
			// cout<<endl;
		}
		// cout<<"final s: "; for (auto it:s) cout<<it.l<<','<<it.r<<','<<it.t<<"  "; cout<<endl;
		for (int i=1; i<=m; ++i) printf("%lld\n", (ans[i]%mod+mod)%mod);
		exit(0);
	}
}

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

	n=read(); m=read();
	for (int i=1; i<=n; ++i) l[i]=read(), r[i]=read()-1;
	for (int i=1; i<=m; ++i) a[i]=read(), b[i]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-09-19 08:41  Administrator-09  阅读(1)  评论(0编辑  收藏  举报