20200711

今天补了一下暑期嗨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;
}

你可能感兴趣的:(20200711)