链接
AC的做法
枚举颜色,然后考虑我可以点亮某个点或者熄灭某个点,以点亮某个点为例,假设这个点是
i
i
i,枚举树上已经被点亮的点
j
j
j,那么此时答案的增量为
∑
j
(
d
e
p
t
h
i
+
d
e
p
t
h
j
−
2
d
e
p
t
h
l
c
a
(
i
,
j
)
)
w
i
w
j
P
\sum_{j} (depth_i+depth_j-2depth_{lca(i,j)})w_iw_jP
j∑(depthi+depthj−2depthlca(i,j))wiwjP
其中 P = ∏ ( r i − l i + 1 ) , w i = ( r i − l i + 1 ) − 1 P = \prod (r_i-l_i+1),w_i = (r_i-l_i+1)^{-1} P=∏(ri−li+1),wi=(ri−li+1)−1
化简一下得到
P
w
i
(
d
e
p
t
h
i
∑
j
d
e
p
t
h
j
+
∑
j
w
j
d
e
p
t
h
j
−
2
∑
j
d
e
p
t
h
l
c
a
(
i
,
j
)
w
j
)
P w_i \left( depth_i \sum_{j} depth_j + \sum_{j} w_j depth_j - 2 \sum_{j} depth_{lca(i,j)}w_j \right)
Pwi(depthij∑depthj+j∑wjdepthj−2j∑depthlca(i,j)wj)
一共三项,前两项都很容易维护
第三项,我可以对于已存在的 j j j,把根节点到 j j j的每个节点的权值都 + = w j +=w_j +=wj,那么 i i i到根节点这条路径上的权值之和就是第三项
AC的代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 100010
#define maxe 200010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
#define mod 1000000007ll
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
ll ans, n, l[maxn], r[maxn], inv[maxn], P, now, w[maxn];
struct SegmentTree
{
ll sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
void maketag_set(ll o, ll v)
{
add[o]=0;
set[o]=v;
sum[o]=(R[o]-L[o]+1)*v;
}
void maketag_add(ll o, ll v)
{
(add[o]+=v)%=mod;
(sum[o]+=(R[o]-L[o]+1)*v)%=mod;
}
void pushdown(ll o)
{
if(L[o]==R[o])return;
if(~set[o])
{
maketag_set(o<<1,set[o]);
maketag_set(o<<1|1,set[o]);
set[o]=-1;
}
if(add[o])
{
maketag_add(o<<1,add[o]);
maketag_add(o<<1|1,add[o]);
add[o]=0;
}
}
void pushup(ll o)
{
(sum[o]=sum[o<<1]+sum[o<<1|1])%mod;
}
void build(ll o, ll l, ll r)
{
ll mid(l+r>>1);
L[o]=l, R[o]=r;
add[o]=0;
set[o]=-1;
if(l==r)
{
return;
}
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
void segset(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
pushdown(o);
if(l<=mid)segset(o<<1,l,r,v);
if(r>mid)segset(o<<1|1,l,r,v);
pushup(o);
}
void segadd(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
pushdown(o);
if(l<=mid)segadd(o<<1,l,r,v);
if(r>mid)segadd(o<<1|1,l,r,v);
pushup(o);
}
ll segsum(ll o, ll l, ll r)
{
pushdown(o);
ll mid(L[o]+R[o]>>1), ans(0);
if(l<=L[o] and r>=R[o])return sum[o];
if(l<=mid)ans+=segsum(o<<1,l,r);
if(r>mid)ans+=segsum(o<<1|1,l,r);
return ans%mod;
}
}segtree;
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe], w[maxe];
void clear(int N)
{
for(int i=1;i<=N;i++)head[i]=0;
etot=0;
}
void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
#define forp(pos,G) for(auto p=G.head[pos];p;p=G.next[p])
}G;
struct Heavy_Light_Decomposition
{
int size[maxn], top[maxn], tid[maxn], tim, untid[maxn], depth[maxn], son[maxn], fa[maxn];
void dfs1(Graph &G, int pos)
{
int p, v;
size[pos]=1;
for(p=G.head[pos];p;p=G.next[p])
{
if((v=G.to[p])==fa[pos])continue;
fa[v]=pos;
depth[v]=depth[pos]+1;
dfs1(G,v);
if(size[v]>size[son[pos]])son[pos]=v;
size[pos]+=size[v];
}
}
void dfs2(Graph &G, int pos, int tp)
{
int p, v;
top[pos]=tp;
tid[pos]=++tim;
untid[tid[pos]]=pos;
if(son[pos])dfs2(G,son[pos],tp);
for(p=G.head[pos];p;p=G.next[p])
if((v=G.to[p])!=fa[pos] and v!=son[pos])dfs2(G,v,v);
}
void run(Graph &G, int root)
{
tim=0;
depth[root]=1;
dfs1(G,root);
dfs2(G,root,root);
}
}HLD;
vector<pll> events[maxn];
int main()
{
ll n, i;
inv[1]=1;
for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
n=read();
P=1;
rep(i,n)
{
l[i]=read(), r[i]=read();
(P*=r[i]-l[i]+1)%=mod;
w[i]=inv[r[i]-l[i]+1];
events[l[i]].emb( pll(i,+1) );
events[r[i]+1].emb( pll(i,-1) );
}
rep(i,n-1)
{
int u=read(), v=read();
G.adde(u,v), G.adde(v,u);
}
HLD.run(G,1);
segtree.build(1,1,n);
ll sw=0, sdw=0;
rep(i,1e5)
{
for(auto e:events[i])
{
auto pos=e.fi, v=e.se;
ll delt=0;
(delt += HLD.depth[pos]*sw)%=mod;
(delt += sdw)%=mod;
ll s=0, x=pos;
while(x)
{
auto tp = HLD.top[x];
(s+=segtree.segsum(1,HLD.tid[tp],HLD.tid[x]))%=mod;
x=HLD.fa[tp];
}
(delt -= 2*s)%=mod;
(now+=v*P*w[pos]%mod*delt)%=mod;
x=pos;
while(x)
{
auto tp = HLD.top[x];
segtree.segadd(1,HLD.tid[tp],HLD.tid[x],w[pos]*v);
x=HLD.fa[tp];
}
(sw+=v*w[pos])%=mod;
(sdw+=v*w[pos]*HLD.depth[pos])%=mod;
}
(ans+=now)%=mod;
}
cout<<(ans+mod)%mod;
return 0;
}
因为常数太大而 T L E TLE TLE的做法
点分治,一棵子树一棵子树的进行合并
新来一棵子树的时候,我就对于每个节点都求一下它颜色区间的深度和,这是路径的一段,另一段可以通过维护每种颜色被多少个点包含了进而算出来
两个线段树可能常数比较大?
而且实际上线段树操作的调用次数也比前一种算法多,所以就
T
L
E
TLE
TLE了
因为常数太大而 T L E TLE TLE的代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 100010
#define maxe 200010
#define maxk 17
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
#define mod 1000000007ll
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
ll ans, n, l[maxn], r[maxn], inv[maxn], P;
struct SegmentTree
{
ll sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
void maketag_set(ll o, ll v)
{
add[o]=0;
set[o]=v;
sum[o]=(R[o]-L[o]+1)*v;
}
void maketag_add(ll o, ll v)
{
(add[o]+=v)%=mod;
(sum[o]+=(R[o]-L[o]+1)*v)%=mod;
}
void pushdown(ll o)
{
if(L[o]==R[o])return;
if(~set[o])
{
maketag_set(o<<1,set[o]);
maketag_set(o<<1|1,set[o]);
set[o]=-1;
}
if(add[o])
{
maketag_add(o<<1,add[o]);
maketag_add(o<<1|1,add[o]);
add[o]=0;
}
}
void pushup(ll o)
{
(sum[o]=sum[o<<1]+sum[o<<1|1])%mod;
}
void build(ll o, ll l, ll r)
{
ll mid(l+r>>1);
L[o]=l, R[o]=r;
add[o]=0;
set[o]=-1;
if(l==r)
{
return;
}
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
void segset(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
pushdown(o);
if(l<=mid)segset(o<<1,l,r,v);
if(r>mid)segset(o<<1|1,l,r,v);
pushup(o);
}
void segadd(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
pushdown(o);
if(l<=mid)segadd(o<<1,l,r,v);
if(r>mid)segadd(o<<1|1,l,r,v);
pushup(o);
}
ll segsum(ll o, ll l, ll r)
{
pushdown(o);
ll mid(L[o]+R[o]>>1), ans(0);
if(l<=L[o] and r>=R[o])return sum[o];
if(l<=mid)ans+=segsum(o<<1,l,r);
if(r>mid)ans+=segsum(o<<1|1,l,r);
return ans%mod;
}
}sum_tree, cnt_tree;
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe], w[maxe];
void clear(int N)
{
for(int i=1;i<=N;i++)head[i]=0;
etot=0;
}
void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
#define forp(pos,G) for(auto p=G.head[pos];p;p=G.next[p])
}G;
struct Centroid_Decomposition
{
ll grey[maxn], depth[maxn], size[maxn], dist[maxn], lis[maxn];
void dfs(ll pos, ll pre, Graph& G)
{
lis[++*lis]=pos;
// lis.emb(pos);
// de(pos);
size[pos]=1;
forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
{
depth[G.to[p]]=depth[pos]+1;
dist[G.to[p]]=dist[pos]+G.w[p];
dfs(G.to[p],pos,G);
size[pos]+=size[G.to[p]];
}
}
void findG(ll pos, ll pre, Graph& G, ll& g, ll& gsum, ll nowsum, ll node_tot)
{
if(nowsum<gsum)g=pos, gsum=nowsum;
forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
findG( G.to[p], pos, G, g, gsum, nowsum+(node_tot-2*size[G.to[p]]), node_tot );
}
void solve(ll pos, Graph& G)
{
*lis=0; dfs(pos,0,G);
ll g=pos, gsum=0, i;
rep(i,*lis)gsum+=depth[lis[i]];//, cerr<<x<<'('<<size[x]<<')'<<' ';cerr<<endl;
findG(pos,0,G,g,gsum,gsum,*lis);
grey[g]=1;
//--- process ---
sum_tree.segset(1,1,1e5,0);
cnt_tree.segset(1,1,1e5,0);
forp(g,G)if(!grey[G.to[p]])
{
depth[G.to[p]]=1;
*lis=0;dfs(G.to[p],g,G);
rep(i,*lis)
{
auto x=lis[i];
ans += sum_tree.segsum(1,l[x],r[x])*inv[r[x]-l[x]+1]%mod;
ans += cnt_tree.segsum(1,l[x],r[x])*depth[x]%mod*inv[r[x]-l[x]+1]%mod;
ans%=mod;
}
rep(i,*lis)
{
auto x=lis[i];
sum_tree.segadd(1,l[x],r[x],depth[x]*inv[r[x]-l[x]+1]%mod*P%mod);
cnt_tree.segadd(1,l[x],r[x],inv[r[x]-l[x]+1]*P%mod);
}
}
(ans+=sum_tree.segsum(1,l[g],r[g])*inv[r[g]-l[g]+1])%=mod; //不要忘记处理一端在重心的路径
//---------------
forp(g,G)if(!grey[G.to[p]])solve(G.to[p],G);
}
}CD;
int main()
{
int n, i;
inv[1]=1;
for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
n=read();
P=1;
rep(i,n)
{
l[i]=read(), r[i]=read();
(P*=r[i]-l[i]+1)%=mod;
}
rep(i,n-1)
{
int u=read(), v=read();
G.adde(u,v), G.adde(v,u);
}
// de("debug1");
sum_tree.build(1,1,1e5);
cnt_tree.build(1,1,1e5);
// de("debug2");
CD.solve(1,G);
cout<<ans;
return 0;
}