BZOJ 3648 寝室管理
【题解】
GDOI2016 Day2T3
如果给出的数据是一棵树那么皆大欢喜直接点分治就好了,用树状数组维护大于x的数的个数。如果是一棵基环树,我们先断掉环上的一条边,然后跑点分治;再加上经过这条边的方案数,其实就是从断掉的那条边的一个端点开始,把环遍历一遍,更新贡献的方式跟点分治过程中的差不多,具体看注释2333。
1 #include<cstdio> 2 #include<algorithm> 3 #define rg register 4 #define N 100010 5 #define LL long long 6 using namespace std; 7 int n,m,k,tot,cnt,top,cir,root; 8 int last[N],dep[N],bit[N<<1],siz[N],mxsiz[N],st[N],c[N]; 9 bool cut[N<<1],v[N]; 10 LL ans=0; 11 struct edge{ 12 int to,pre,dis; 13 }e[N<<1]; 14 inline int read(){ 15 int k=0,f=1; char c=getchar(); 16 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 17 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 18 return k*f; 19 } 20 inline void add(int x,int y){for(;x>0;x-=(x&-x))bit[x]+=y;} 21 inline int query(int x){ 22 if(x<1) x=1; int ret=0; 23 for(;x<=n+cir;x+=(x&-x)) ret+=bit[x]; return ret; 24 } 25 void findcircle(int x,int fa){ 26 if(cir) return; 27 if(v[x]){ 28 c[cir=1]=x; 29 for(rg int i=top;st[i]!=x;c[++cir]=st[i--]); 30 } 31 v[x]=1; st[++top]=x; 32 for(rg int i=last[x],to;i;i=e[i].pre) 33 if((to=e[i].to)!=fa) findcircle(to,x); 34 v[x]=0; top--; 35 } 36 void getroot(int x,int fa){ 37 siz[x]=1; mxsiz[x]=0; 38 for(rg int i=last[x],to;i;i=e[i].pre)if(!v[to=e[i].to]&&to!=fa&&!cut[i]){ 39 getroot(to,x); siz[x]+=siz[to]; 40 mxsiz[x]=max(mxsiz[x],siz[to]); 41 } 42 mxsiz[x]=max(mxsiz[x],cnt-mxsiz[x]); 43 if(!root||mxsiz[x]<mxsiz[root]) root=x; 44 } 45 void getdep(int x,int fa,int d){ 46 st[++top]=d; 47 for(rg int i=last[x],to;i;i=e[i].pre) 48 if(!v[to=e[i].to]&&to!=fa&&!cut[i]) getdep(to,x,d+1); 49 } 50 void dfs(int x){ 51 int l=0; v[x]=1; 52 for(rg int i=last[x],to;i;i=e[i].pre) 53 if(!v[to=e[i].to]&&!cut[i]){ 54 l=top+1; getdep(to,x,1); 55 for(rg int j=l;j<=top;j++) ans+=query(k-st[j]-1); 56 for(rg int j=l;j<=top;j++) add(st[j],1); 57 } 58 ans+=query(k-1); 59 while(top) add(st[top--],-1); 60 for(rg int i=last[x],to;i;i=e[i].pre) 61 if(!v[to=e[i].to]&&!cut[i]&&siz[to]>=k){ 62 cnt=siz[to]; root=0; getroot(to,x); dfs(root); 63 } 64 } 65 int main(){ 66 n=read(); m=read(); k=read(); 67 for(rg int i=1;i<=m;i++){ 68 int u=read(),v=read(); 69 e[++tot]=(edge){v,last[u]}; last[u]=tot; 70 e[++tot]=(edge){u,last[v]}; last[v]=tot; 71 } 72 if(m<n){ 73 cnt=n; root=0; getroot(1,0); dfs(root); 74 } 75 else{ 76 findcircle(1,0); 77 for(rg int i=last[c[1]],to;i;i=e[i].pre)if((to=e[i].to)==c[cir]){ 78 cut[i]=1; break; 79 } 80 for(rg int i=last[c[cir]],to;i;i=e[i].pre)if((to=e[i].to)==c[1]){ 81 cut[i]=1; break; 82 } 83 top=0; cnt=n; root=0; 84 getroot(1,0); dfs(root); 85 top=0; 86 for(rg int i=1;i<=n;i++)v[i]=0; 87 for(rg int i=1;i<=cir+n;i++) bit[i]=0; 88 for(rg int i=1;i<=cir;i++) v[c[i]]=1; 89 for(rg int i=1;i<=cir;i++){ 90 v[c[i]]=0; 91 getdep(c[i],0,0); 92 v[c[i]]=1; 93 for(rg int j=1;j<=top;j++)ans+=query(k-(cir-i+1)-st[j]);//cir-i+1是绕一圈到环上起点的距离 94 while(top) add(st[top--]+i,1);//+i就是加上到环上起点的距离 95 } 96 } 97 printf("%lld\n",ans); 98 return 0; 99 }