BZOJ 3772 精神污染
2018.01.13
2018.01.13
给你一棵树和树上的一些路径,求有多少路径A包含路径B的情况。
扫描线+树状数组,代码不忍直视,注意边要depth[u]<depth[v],不能u<v.
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
inline char nc()
{
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int RI()
{
int ret=0;char tmp=nc();
while(!isdigit(tmp)) tmp=nc();
while(isdigit(tmp)) ret=ret*10+(tmp^'0'),tmp=nc();
return ret;
}
#define N 100010
struct edge{int u,v;}e[N];
struct point{int x,y,id;}p[N<<1];
struct query{int x,y,id,res,mus;}q[N<<3];
bool cmpp(const point &X,const point &Y){return X.x==Y.x?X.y<Y.y:X.x<Y.x;}
bool cmpq(const query &X,const query &Y){return X.x==Y.x?X.y<Y.y:X.x<Y.x;}
bool back(const query &X,const query &Y){return X.id<Y.id;}
int n,m,cq,rka[N],rkb[N],bit[N<<1],cnt,fa[N][21],depth[N],lg[N];
int to[N<<1],nxt[N<<1],head[N],tot;
inline void AE(int X,int Y){to[++tot]=Y,nxt[tot]=head[X],head[X]=tot;}
void DFS(int pos,int pre)
{
for(int i=1;i<=lg[n];++i) fa[pos][i]=fa[fa[pos][i-1]][i-1];
rka[pos]=++cnt;
for(int i=head[pos];i;i=nxt[i]) if(to[i]!=pre) depth[to[i]]=depth[pos]+1,fa[to[i]][0]=pos,DFS(to[i],pos);
rkb[pos]=++cnt;
}
inline void insert(int X){for(;X<=(n<<1);X+=X&-X) bit[X]++;}
inline int query(int X)
{
int ret=0;
for(;X;X-=X&-X) ret+=bit[X];
return ret;
}
long long gcd(long long X,long long Y){return Y?gcd(Y,X%Y):X;}
bool sameline(int X,int Y)
{
for(int i=lg[n];~i;i--) if(depth[fa[Y][i]]>=depth[X]) Y=fa[Y][i];
return X==Y;
}
int getfa(int X,int Y)
{
int tmp=depth[X]+1;
for(int i=lg[n];~i;i--) if(depth[fa[Y][i]]>=tmp) Y=fa[Y][i];
return Y;
}
int main()
{
int X,Y;
n=RI(),m=RI();
for(int i=2;i<=n;++i) X=RI(),Y=RI(),AE(X,Y),AE(Y,X),lg[i]=lg[i>>1]+1;
depth[1]=1,DFS(1,0);
for(int i=1;i<=m;++i)
{
e[i].u=RI(),e[i].v=RI();
if(depth[e[i].u]>depth[e[i].v]) swap(e[i].u,e[i].v);
}
for(int i=1;i<=m;++i)
{
p[i].id=i,p[i].x=rka[e[i].u],p[i].y=rka[e[i].v];
p[i+m].id=i,p[i+m].x=rka[e[i].v],p[i+m].y=rka[e[i].u];
}
sort(p+1,p+(m<<1)+1,cmpp);
for(int i=1;i<=m;++i)
{
if(sameline(e[i].u,e[i].v))
{
int tmp=getfa(e[i].u,e[i].v);
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rkb[1],q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rka[1]-1,q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rka[1]-1,q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rkb[1],q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rkb[tmp],q[cq].mus=-1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rka[tmp]-1,q[cq].mus=-1;
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rka[tmp]-1,q[cq].mus=-1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rkb[tmp],q[cq].mus=-1;
}
else
{
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rkb[e[i].u],q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rka[e[i].u]-1,q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rkb[e[i].v],q[cq].y=rka[e[i].u]-1,q[cq].mus=1;
++cq,q[cq].id=cq,q[cq].x=rka[e[i].v]-1,q[cq].y=rkb[e[i].u],q[cq].mus=1;
}
}
sort(q+1,q+cq+1,cmpq);
for(int i=1,j=1;i<=cq;++i)
{
for(;j<=(m<<1)&&p[j].x<=q[i].x;++j) insert(p[j].y);
q[i].res=query(q[i].y);
}
sort(q+1,q+cq+1,back);
long long rX=-m,rY=1ll*m*(m-1)/2;
for(int i=1;i<=cq;i+=4)
rX+=(q[i].res+q[i+1].res-q[i+2].res-q[i+3].res)*q[i].mus;
long long tmp=gcd(rX,rY);rX/=tmp,rY/=tmp;
printf("%lld/%lld\n",rX,rY);
return 0;
}