点分治+线段树(过不去)。
把点分治换成DSU ON THE TREE 应该就能过了。
设S为∏(R[i]-L[i]+1),W[i]为(R[i]-L[i]+1)。
假设有一个点u,则它对答案的贡献为∑(disu + disv) * (S / (W[u] * W[v])),条件为u和v的区间有交。
把式子拆开有两个项,分别用线段树维护即可。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cmath> #include<cstring> #include<string> using namespace std; char gc() { static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } int getnum() { int x = 0, f = 1; char ch = gc(); while (ch < ‘0‘ || ch > ‘9‘) { if (ch == ‘-‘) f = -1; ch = gc(); } while (ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = gc(); } return x * f; } const int N = 100010, up = 100000, mo = 1e9 + 7; int n, P; int cnt; int head[N]; struct edge { int v, nxt; } vec[N << 1]; int L[N]; int R[N]; int G[N]; int ksm(int a, int b) { int s = 1; while (b) { if (b & 1) s = 1LL * s * a % mo; a = 1LL * a * a % mo; b >>= 1; } return s; } int add(int a, int b) { a += b; if (a >= mo) a -= mo; if (a < 0) a += mo; return a; } pair<int, int> operator + (pair<int, int> a, pair<int, int> b) { return make_pair(add(a.first, b.first), add(a.second, b.second)); } struct SEG { #define lson (o << 1) #define rson (o << 1 | 1) int sum[N << 2]; int flag[N << 2]; int ss[N << 2]; int hh[N << 2]; void pushup(int o) { sum[o] = add(sum[lson], sum[rson]); ss[o] = add(ss[lson], ss[rson]); } void pushdown(int o, int l, int r) { if (flag[o]) { flag[lson] = add(flag[lson], flag[o]); flag[rson] = add(flag[rson], flag[o]); int mid = (l + r) >> 1; sum[lson] = add(sum[lson], 1LL * flag[o] * (mid - l + 1) % mo); sum[rson] = add(sum[rson], 1LL * flag[o] * (r - mid) % mo); flag[o] = 0; } if (hh[o]) { hh[lson] = add(hh[lson], hh[o]); hh[rson] = add(hh[rson], hh[o]); int mid = (l + r) >> 1; ss[lson] = add(ss[lson], 1LL * hh[o] * (mid - l + 1) % mo); ss[rson] = add(ss[rson], 1LL * hh[o] * (r - mid) % mo); hh[o] = 0; } } void modify(int o, int l, int r, int L, int R, int p, int v) { if (L <= l && r <= R) { flag[o] = add(flag[o], p); sum[o] = add(sum[o], 1LL * p * (r - l + 1) % mo); hh[o] = add(hh[o], v); ss[o] = add(ss[o], 1LL * v * (r - l + 1) % mo); return; } pushdown(o, l, r); int mid = (l + r) >> 1; if (L <= mid) modify(lson, l, mid, L, R, p, v); if (R > mid) modify(rson, mid + 1, r, L, R, p, v); pushup(o); } pair<int, int> query(int o, int l, int r, int L, int R) { if (L <= l && r <= R) return make_pair(sum[o], ss[o]); pushdown(o, l, r); int mid = (l + r) >> 1; pair<int, int> ret = make_pair(0, 0); if (L <= mid) ret = ret + query(lson, l, mid, L, R); if (R > mid) ret = ret + query(rson, mid + 1, r, L, R); pushup(o); return ret; } void output() { for (int i = 1; i <= 20; ++i) printf("%d ", hh[i]); printf("\n"); for (int i = 1; i <= 20; ++i) printf("%d ", ss[i]); printf("\n\n"); } } SEG; int S, rt, minn; int ans; int siz[N]; bool vis[N]; void addedge(int u, int v) { vec[++cnt] = (edge){v, head[u]}; head[u] = cnt; } void get_read() { n = getnum(); for (int i = 1; i <= n; ++i) L[i] = getnum(), R[i] = getnum(); for (int i = 1; i <= n - 1; ++i) { int u = getnum(), v = getnum(); addedge(u, v); addedge(v, u); } } void getroot(int u, int fa) { int ret = 0; siz[u] = 1; for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (v == fa || vis[v]) continue; getroot(v, u); siz[u] += siz[v]; ret = max(ret, siz[v]); } ret = max(ret, S - siz[u]); if (ret < minn) minn = ret, rt = u; } void pd(int u, int fa, int w) { pair<int, int> X = SEG.query(1, 1, up, L[u], R[u]); ans = add(ans, 1LL * G[u] % mo * P % mo * add(1LL * X.second * w % mo, X.first) % mo); for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (v == fa || vis[v]) continue; pd(v, u, w + 1); } } void solve(int u, int fa, int w, int c) { SEG.modify(1, 1, up, L[u], R[u], 1LL * c * w % mo * G[u] % mo, 1LL * c % mo * G[u] % mo); for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (v == fa || vis[v]) continue; solve(v, u, w + 1, c); } } void calc(int u) { for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (vis[v]) continue; pd(v, u, 1); solve(v, u, 1, 1); } ans = add(ans, 1LL * SEG.query(1, 1, up, L[u], R[u]).first * P % mo * G[u] % mo); for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (vis[v]) continue; solve(v, u, 1, -1); } } void divide(int u) { vis[u] = true; calc(u); for (int i = head[u]; i; i = vec[i].nxt) { int v = vec[i].v; if (vis[v]) continue; S = siz[v]; rt = v; minn = siz[v]; getroot(v, u); divide(rt); } } void get_work() { P = 1; for (int i = 1; i <= n; ++i) { P = 1LL * P * (R[i] - L[i] + 1) % mo; G[i] = ksm(R[i] - L[i] + 1, mo - 2); } S = n; rt = 1; minn = n; getroot(1, 0); divide(rt); printf("%d", (ans % mo + mo) % mo); } signed main() { get_read(); get_work(); return 0; }
原文地址:https://www.cnblogs.com/calvin99/p/12037682.html
时间: 2024-10-13 16:33:06