BZOJ3648: 寝室管理
2016-11-16 07:19
169 查看
比较裸的点分,因为图是由一棵树加一条边组成,所以只会有一个环,找到这个环然后随便拿掉一条边做点分,然后再考虑经过这条边的路径,沿着环走一圈就行了
#include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<cmath> #include<ctime> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long #define lowbit(x) x&(-x) using namespace std; const int maxn = 210000; struct edge { int y,nex; edge(){} edge(int _y,int _nex){y=_y;nex=_nex;} }a[maxn]; int len,fir[maxn]; void ins(int x,int y){a[++len]=edge(y,fir[x]);fir[x]=len;} int n,m,K; bool cc[maxn]; int siz[maxn]; int t[maxn],tp=0,circle[maxn],clen,ce,ce2; bool find_circle(int x,int f) { t[++tp]=x; if(cc[x]) { clen=0; while(t[tp-1]!=x) circle[++clen]=t[tp--]; circle[++clen]=t[tp]; return true; } cc[x]=true; for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; if(y!=f) { if(find_circle(y,x))return true; } } cc[x]=false; tp--; return false; } void find_root(int x,int f,int &rt,int sum) { siz[x]=1; bool flag=true; for(int k=fir[x];k;k=a[k].nex) { if(k==ce||k==ce2)continue; int y=a[k].y; if(y!=f&&!cc[y]) { find_root(y,x,rt,sum); siz[x]+=siz[y]; if(siz[y]*2>sum) flag=false; } } if((sum-siz[x])*2>sum) flag=false; if(flag) rt=x; } int s[maxn],v[maxn],vlen; ll ret; void dfs(int x,int f,int r,int pos) { r++; s[++tp]=r; while(pos<vlen&&r+1>=v[pos+1]) pos++; if(r+1>=v[pos]) ret+=(ll)pos; for(int k=fir[x];k;k=a[k].nex) { if(k==ce||k==ce2)continue; int y=a[k].y; if(y!=f&&!cc[y]) dfs(y,x,r,pos); } } void solve(int x,int sum) { find_root(x,0,x,sum); cc[x]=true; v[vlen=1]=K; for(int k=fir[x];k;k=a[k].nex) { if(k==ce||k==ce2)continue; int y=a[k].y; if(!cc[y]) { tp=0; dfs(y,x,0,0); for(int i=1;i<=tp;i++) v[++vlen]=K-s[i]; sort(v+1,v+vlen+1); } } vlen=0; for(int k=fir[x];k;k=a[k].nex) { if(k==ce||k==ce2)continue; int y=a[k].y; if(!cc[y]) { int tt=siz[y]>siz[x]?sum-siz[x]:siz[y]; solve(y,tt); } } } bool mark[maxn]; vector<int>u[maxn]; void build_v(int rt,int x,int f,int r) { r++; u[rt].push_back(r); for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; if(y!=f&&!mark[k]) build_v(rt,y,x,r); } } int add(int *qs,int x,int c) { x=max(K-x+1,1); while(x<=n){qs[x]+=c;x+=lowbit(x);} } ll qy(int *qs,int x) { x++; ll rr=0; for(;x;x-=lowbit(x))rr+=(ll)qs[x]; return rr; } int main() { memset(fir,0,sizeof fir); len=1; ce=ce2=0; ret=0; scanf("%d%d%d",&n,&m,&K); if(K==0){printf("0\n"); return 0;} for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); ins(x,y); ins(y,x); } if(n==m) { find_circle(1,0); for(int k=fir[circle[1]];k;k=a[k].nex) if(a[k].y==circle[2]) {ce=k;break;} ce2=ce^1; memset(cc,false,sizeof cc); } solve(1,n); if(n==m) { for(int i=1;i<=clen;i++) { int x=circle[i]; for(int k=fir[x];k;k=a[k].nex) { if(i==1) { if(a[k].y==circle[2]||a[k].y==circle[clen]) mark[k]=true; } else if(i==clen) { if(a[k].y==circle[1]||a[k].y==circle[clen-1]) mark[k]=true; } else { if(a[k].y==circle[i-1]||a[k].y==circle[i+1]) mark[k]=true; } } build_v(x,x,x,0); } memset(v,0,sizeof v); for(int i=2;i<=clen;i++) { int x=circle[i]; for(int j=0;j<u[x].size();j++) { int ts=u[x][j]; add(v,ts+clen-i+1,1); } } for(int i=0;i<u[circle[1]].size();i++) add(v,u[circle[1]][i],1); for(int i=2;i<=clen;i++) { int x=circle[i]; tp=0; for(int j=0;j<u[x].size();j++) t[++tp]=u[x][j]; for(int j=1;j<=tp;j++) add(v,t[j]+clen-i+1,-1); for(int j=1;j<=tp;j++) ret+=qy(v,t[j]+i-2); } } printf("%lld\n",ret); return 0; }
相关文章推荐
- BZOJ3648 寝室管理 【点分治 + 环套树】
- bzoj3648 寝室管理
- [BZOJ3648]寝室管理(点分治+bit)
- 【BZOJ3648】寝室管理 树分治
- BZOJ3648 : 寝室管理
- 【bzoj3648】【寝室管理】【环套树+点分治+树状数组】
- [JZOJ3978] 寝室管理
- [树的点分治] [BZOJ3648] 寝室管理
- 学生寝室管理系统
- 用C#做的一个小项目,寝室管理系统
- 寝室管理
- BZOJ 3648|寝室管理|点分治|树状数组|平衡树
- 【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治
- bzoj3648 寝室管理 树分治
- BZOJ 3648: 寝室管理 树的点分治+乱搞
- BZOJ 3648: 寝室管理( 点分治 + 树状数组 )
- 微软项目管理软件的二次开发
- 企业知识管理实施的五个步骤
- 局域网内部管理行为应该如何控制?
- Sun Cluster 3.0 的规划、安装、配置及管理