r 64 有一个好朋友,叫r 128 。r 128 是寄宿生,并且最近被老师叫过去当宿管了。宿
管可不是一件很好做的工作,碰巧r 128 有一个工作上的问题想请r 64 帮忙解决。
r 128 的寝室条件不是很好,所以没有很多钱来装修。n间寝室仅由n − 1条双向道
路连接,而且任意两间寝室之间都可以互达。最近,r 128 被要求对一条路径上的所有
寝室进行管理, 这条路径不会重复经过某个点或某条边。 但他不记得是哪条路径了。
他只记得这条路径上有不少于k个寝室。于是,他想请r 64 帮忙数一下,有多少条这
样的路径满足条件。
嗯...还有一个问题。由于最近有一些熊孩子不准晚上讲话很不爽,他们决定修筑
一条“情报通道”,如果通道建成,寝室就变成了一个n个点n条边的无向图。并且,
经过“情报通道”的路径也是合法的。r 128 心想:通道建成之前,r 64 还有一个高效
的算法帮我数路径条数,但是通道建成之后,他还有办法吗?对,r 64 手忙脚乱,根
本数不清有多少条路径。于是他找到了你。
这道题考场时脑瘫了,50分的暴力打了点分治。
正解也是点分治,对于n=m的情况,可以将环上某一条边去掉,转化成一棵树,用点分治求答案。
然后再单独考虑这个环的情况,可以从断边的一个端点开始扫,统计这个端点顺时针走到断边的答案,再将这个端点逆时针走到端点的答案加入到线段树中。
这里偷一个大佬博客的图。
#include<cstdio> #include<cstring> #include<algorithm> #define N 300000 #define ll long long using namespace std; ll n,m,len,i,j,x,y,q[N],size[N],sizen,root,mxs[N],tot,ans,num,a[N],bz[N],bzp[N],bzx,bzy; ll stk[N],top,hu[N],cnt,ls[N],bzf[N]; struct edge{ ll to,next; }e[N]; struct node{ ll sum; }f[N*10]; void insert(ll x,ll y){ tot++; e[tot].to=y; e[tot].next=q[x]; q[x]=tot; } void getroot(ll x,ll father){ ll i,y; size[x]=1; mxs[x]=0; for (i=q[x];i;i=e[i].next){ y=e[i].to; if (x==bzx&&y==bzy||x==bzy&&y==bzx) continue; if (y!=father&&!bz[y]){ getroot(y,x); size[x]+=size[y]; mxs[x]=max(mxs[x],size[y]); } } mxs[x]=max(mxs[x],sizen-size[x]); if (mxs[x]<mxs[root]) root=x; } void dfs1(ll x,ll ed,ll father,ll opt){ a[++num]=ed; ll i,y; for (i=q[x];i;i=e[i].next){ y=e[i].to; if (x==bzx&&y==bzy||x==bzy&&y==bzx) continue; if (y!=father&&bz[y]==0&&opt==1||y!=father&&opt==0&&bzf[y]==0) dfs1(y,ed+1,x,opt); } } ll getans(ll x,ll ed){ num=0; dfs1(x,ed,0,1); ll l=1,r=num,sum=0; sort(a+1,a+num+1); while (true){ while (l<=num&&a[l]+a[r]<len) l++; if (r<l) break; sum+=r-l; if (a[r]>=len) sum++; r--; } return sum; } void dfs(ll x){ ans+=getans(x,0); ll i,y; bz[x]=1; for (i=q[x];i;i=e[i].next){ y=e[i].to; if (x==bzx&&y==bzy||x==bzy&&y==bzx) continue; if (!bz[y]){ ans-=getans(y,1); root=0; sizen=size[y]; getroot(y,0); dfs(root); } } } void dfsp(ll x,ll father){ ll i,y; if (bzp[x]){ bzx=x; bzy=father; while (stk[top]!=x){ hu[++cnt]=stk[top]; ls[cnt]=ls[cnt-1]+1; bzf[stk[top]]=1; top--; } hu[++cnt]=stk[top]; ls[cnt]=ls[cnt-1]+1; bzf[stk[top]]=1; top--; return; } bzp[x]=1; stk[++top]=x; for (i=q[x];i;i=e[i].next){ y=e[i].to; if (y!=father) dfsp(y,x); if (bzx) return; } top--; } void change(ll x,ll l,ll r,ll k){ if (l==r){ f[x].sum++; return; } ll mid=(l+r)/2; if (k<=mid) change(x*2,l,mid,k); else change(x*2+1,mid+1,r,k); f[x].sum=f[x*2].sum+f[x*2+1].sum; } ll find(ll x,ll l,ll r,ll l1,ll r1){ if (l1<=l&&r1>=r) return f[x].sum; ll sum=0,mid=(l+r)/2; if (l1<=mid) sum+=find(x*2,l,mid,l1,r1); if (r1>mid) sum+=find(x*2+1,mid+1,r,l1,r1); return sum; } int main(){ scanf("%lld%lld%lld",&n,&m,&len); len--; for (i=1;i<=m;i++){ scanf("%lld%lld",&x,&y); insert(x,y); insert(y,x); } dfsp(1,0); mxs[0]=1e9; root=0; sizen=n; getroot(1,0); dfs(root); if (m==n-1){ printf("%lld ",ans); return 0; } num=0; dfs1(bzx,0,0,0); for (i=1;i<=num;i++) change(1,0,n,a[i]); for (i=cnt-1;i>=1;i--){ num=0; dfs1(hu[i],0,0,0); for (j=1;j<=num;j++) ans+=find(1,0,n,len-ls[i]-a[j],n); for (j=1;j<=num;j++) change(1,0,n,a[j]+ls[cnt]-ls[i]); } printf("%lld ",ans); return 0; }