您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: