今天补了一下暑期嗨2的A题,也就是CF1260F。
当天做这套题的时候,其他题对我都没多大难度,但我确实被这道题难住了。我当天想出来了一个点分治的做法,但是拖到今天才写完。
当时我一看就这个题,是一个树上的计数问题,应该是用到(树上DP、树的点分治、数据结构)这一块的知识,而且题型和经典的点分治题目非常像,所以我很快猜到解法用到哪些方面的知识。然而,我点分治掌握的并不熟练,一时半会儿也想不出这道题的解法,只会O(N2)的暴力算法。后来我从网上看了一道点分治的模板题,回忆起了一些知识,对点分治加深了理解之后回头看这道题,想了几个小时终于想出了一个点分治加线段树的解法。(当天大脑状态不太好,效率低了点。)到晚上写了一个框架,最后拖到今天终于完成并调试成功。然而提交到CF上才发现TLE了。数据范围105,我的算法时间复杂度是O(nlog2n)。我自己造105的极限数据测了一下,在我的电脑上需要运行4.3秒左右,然而题目限制的时间只有2.5秒。可以说是被卡常数了。辛辛苦苦完成了二百多行的代码结果最后被卡常数了TAT。不过通过编写这道题的代码,锻炼了我对点分治算法的运用,锻炼了我的代码能力,付出这些时间还是很值得的。这道题正解好像是树链剖分,如果是树剖那么复杂度也是O(nlog2n)。正解有空再补一下。下面附上我的点分治TLE代码。
#include
using namespace std;
typedef long long ll;
const int mxn=200010;
const int mo=1000000007;int n,l[mxn],r[mxn];
int hd[mxn],nx[mxn],v[mxn],e=0;
int iv[mxn];
int dep[mxn];
ll ans=0,rr=1;
bool del[mxn];
//
void ade(int x,int y){
nx[++e]=hd[x];
hd[x]=e;
v[e]=y;
}
struct xds{
int s[mxn],d[mxn],lc[mxn],rc[mxn],n,sz;
int tl[mxn],tr[mxn],tv[mxn],t;
void upd(int x){
s[x]=(s[lc[x]]+s[rc[x]])%mo;
}
int bu(int l,int r){
int x=++sz;
if(l==r){
return x;
}
int mi=(l+r)/2;
lc[x]=bu(l,mi);
rc[x]=bu(mi+1,r);
upd(x);
return x;
}
void init(int nn){
n=nn;
sz=0;
memset(s,0,sizeof(s));
memset(d,0,sizeof(d));
memset(lc,0,sizeof(lc));
memset(rc,0,sizeof(rc));
bu(1,n);
t=0;
}
void add(int x,int l,int r,int v){
d[x]=(d[x]+v)%mo;
s[x]=(s[x]+(ll)(r-l+1)*v)%mo;
}
void xiafang(int x,int l,int r){
if(d[x]==0) return;
int mi=(l+r)/2;
add(lc[x],l,mi,d[x]);
add(rc[x],mi+1,r,d[x]);
d[x]=0;
}
void ins(int x,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr){
add(x,l,r,v);
return;
}
xiafang(x,l,r);
int mi=(l+r)/2;
if(ql<=mi) ins(lc[x],l,mi,ql,qr,v);
if(qr>mi) ins(rc[x],mi+1,r,ql,qr,v);
upd(x);
}
void ins(int l,int r,int v){
v%=mo;
ins(1,1,n,l,r,v);
++t;
tl[t]=l;
tr[t]=r;
tv[t]=v;
// printf("??ins %d %d %d\n",l,r,v);
}
void fuyuan(){
while(t){
ins(1,1,n,tl[t],tr[t],mo-tv[t]);
t--;
}
}
int ans;
void que(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
ans=(ans+s[x])%mo;
return;
}
xiafang(x,l,r);
int mi=(l+r)/2;
if(ql<=mi) que(lc[x],l,mi,ql,qr);
if(qr>mi) que(rc[x],mi+1,r,ql,qr);
}
int que(int l,int r){
ans=0;
que(1,1,n,l,r);
// printf("???%d %d %d\n",l,r,(int)ans*rr%mo);
return ans;
}
} g1,g2;
void ad(int l,int r,int d){
g1.ins(l,r,iv[r-l+1]);
g2.ins(l,r,(ll)iv[r-l+1]*d%mo);
}
void dfs1(int x,int fa){
dep[x]=dep[fa]+1;
// cout<";
ans=(ans+((ll)g1.que(l[x],r[x])*dep[x]+g2.que(l[x],r[x]))%mo*iv[r[x]-l[x]+1])%mo;
ans=(ans+(ll)g1.que(l[x],r[x])*dep[x]%mo*iv[r[x]-l[x]+1])%mo;
// cout<";
ans=(ans+(ll)g2.que(l[x],r[x])*iv[r[x]-l[x]+1])%mo;
// cout<
for(int i=hd[x];i;i=nx[i]){
int y=v[i];
if(del[y]||y==fa) continue;
dfs1(y,x);
}
}
void dfs2(int x,int fa){
ad(l[x],r[x],dep[x]);
for(int i=hd[x];i;i=nx[i]){
int y=v[i];
if(del[y]||y==fa) continue;
dfs2(y,x);
}
}
void sol(int x){
// printf("!!!%d\n",x);
dep[x]=0;
ad(l[x],r[x],dep[x]);
for(int i=hd[x];i;i=nx[i]){
int y=v[i];
if(del[y]) continue;
dfs1(y,x);
dfs2(y,x);
}
ans=(ans+(ll)g2.que(l[x],r[x])*iv[r[x]-l[x]+1])%mo;
g1.fuyuan();
g2.fuyuan();
}
int s[mxn];
void jss(int x,int fa){
s[x]=1;
for(int i=hd[x];i;i=nx[i]){
int y=v[i];
if(del[y]||y==fa) continue;
jss(y,x);
s[x]+=s[y];
}
}
int mnn,zx;
void zzx(int x,int fa,int n){
int mx=n-s[x];
for(int i=hd[x];i;i=nx[i]){
int y=v[i];
if(del[y]||y==fa) continue;
zzx(y,x,n);
mx=max(mx,s[y]);
}
if(mx<mnn){
mnn=mx;
zx=x;
}
}
void dfz(int x){
jss(x,0);
zx=x;
mnn=s[x];
zzx(x,0,s[x]);
sol(zx);
del[zx]=1;
for(int i=hd[zx];i;i=nx[i]){
int y=v[i];
if(del[y]) continue;
dfz(y);
}
}
ll pw(ll a,ll b){
ll r=1;
while(b){
if(b&1) r=r*a%mo;
a=a*a%mo;
b>>=1;
}
return r;
}
void initiv(int n){
for(int i=1;i<=n;i++) iv[i]=pw(i,mo-2);
// for(int i=1;i<=n;i++) printf("%d %d\n",i,iv[i]);
}
int main(){
// freopen("a.in","r",stdin);
scanf("%d",&n);
int mx=1;
for(int i=1;i<=n;i++){
scanf("%d%d",&l[i],&r[i]);
mx=max(mx,r[i]);
}
for(int i=1;i<=n;i++) rr=(rr*(r[i]-l[i]+1))%mo;
// cout<<"???"<
g1.init(mx);
g2.init(mx);
initiv(mx);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
ade(x,y);
ade(y,x);
}
dfz(1);
for(int i=1;i<=n;i++){
ans=ans*(r[i]-l[i]+1)%mo;
}
cout<<ans<<"\n";
return 0;
}