题解 底垫
- 给定 \(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;
}