题意:给你一棵仙人掌,求有多少种方案使得移动一条边之后的图形仍是仙人掌。
题解:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=50005;
struct edge{
int u,v,f,next;
}G[N<<3];
int head[N],inum=1;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m; ll ans;
int pre[N],clk;
int fat[N],fp[N],size[N],nxt[N];
namespace Tset{
int fat[N],size[N],rank[N];
inline void init(int n){
for (int i=1;i<=n;i++)
fat[i]=i,size[i]=1;
}
inline int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
inline void Union(int x,int y){
x=Fat(x); y=Fat(y); if (x==y) return;
if (rank[x]>rank[y]) swap(x,y);
if (rank[x]==rank[y]) rank[y]++;
fat[x]=y; size[y]+=size[x];
}
inline int Size(int u){
return size[Fat(u)];
}
}
#define V G[p].v
inline void dfs(int u,int fa){
pre[u]=++clk; fat[u]=fa;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
{
if (!pre[V]){
fp[V]=p,dfs(V,u);
}
else if (pre[V]<pre[u])
{
G[p].f=G[p^1].f=1;
int i;
nxt[u]=V;
for (i=u;fat[i]!=V;i=fat[i])
{
nxt[fat[i]]=i;
G[fp[i]].f=G[fp[i]^1].f=1;
}
// nxt[fat[i]]=i;
G[fp[i]].f=2; G[fp[i]^1].f=1;
}
}
}
inline void rebuild(int u,int fa){
size[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!G[p].f)
{
rebuild(V,u),size[u]+=size[V];
ans+=(ll)size[V]*(n-size[V])-1;
}
else if (G[p].f==2)
rebuild(V,u),size[u]+=size[V];
if (nxt[u] && pre[nxt[u]]>pre[u])
rebuild(nxt[u],u),size[u]+=size[nxt[u]];
}
ll sum[N],tot;
int main()
{
int iu,iv;
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++)
read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
dfs(1,0);
rebuild(1,0);
Tset::init(n);
for (int u=1;u<=n;u++)
for (int p=head[u];p;p=G[p].next)
if (!G[p].f)
Tset::Union(u,V);
for (int i=1,s;i<=n;i++)
if (Tset::Fat(i)==i && (s=Tset::Size(i))>2)
sum[i]=s*(s-1)/2-(s-1),tot+=sum[i];
for (int u=1;u<=n;u++)
for (int p=head[u];p;p=G[p].next)
if (G[p].f==2)
{
ll ttot=tot;
int len=1;
ll tsum=Tset::Size(u);
ttot-=sum[Tset::Fat(u)];
for (int i=V;i!=u;i=nxt[i])
len++,tsum+=Tset::Size(i),ttot-=sum[Tset::Fat(i)];
ans+=(tsum*(tsum-1)/2-(tsum-1)-1)*len;
ans+=len*ttot;
}
printf("%lld\n",ans);
return 0;
}
UPD160712
BZ上的代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> abcd;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=50005;
struct edge{
int u,v,f,next;
}G[N<<3];
int head[N],inum=1;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m; ll ans;
int pre[N],clk;
int fat[N],fp[N],size[N],nxt[N];
namespace Tset{
int fat[N],size[N],rank[N];
inline void init(int n){
for (int i=1;i<=n;i++)
fat[i]=i,size[i]=1;
}
inline int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
inline void Union(int x,int y){
x=Fat(x); y=Fat(y); if (x==y) return;
if (rank[x]>rank[y]) swap(x,y);
if (rank[x]==rank[y]) rank[y]++;
fat[x]=y; size[y]+=size[x];
}
inline int Size(int u){
return size[Fat(u)];
}
}
#define V G[p].v
inline void dfs(int u,int fa){
pre[u]=++clk; fat[u]=fa;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
{
if (!pre[V]){
fp[V]=p,dfs(V,u);
}
else if (pre[V]<pre[u])
{
G[p].f=G[p^1].f=1;
int i;
nxt[u]=V;
for (i=u;fat[i]!=V;i=fat[i])
{
nxt[fat[i]]=i;
G[fp[i]].f=G[fp[i]^1].f=1;
}
G[fp[i]].f=2; G[fp[i]^1].f=1;
}
}
}
inline void rebuild(int u,int fa){
size[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!G[p].f)
{
rebuild(V,u),size[u]+=size[V];
ans+=(ll)size[V]*(n-size[V])-1;
}
else if (G[p].f==2)
rebuild(V,u),size[u]+=size[V];
if (nxt[u] && pre[nxt[u]]>pre[u])
rebuild(nxt[u],u),size[u]+=size[nxt[u]];
}
ll sum[N],tot;
int main()
{
int iu,iv,k;
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++)
{
read(k); read(iu);
for (int j=2;j<=k;j++)
read(iv),add(iu,iv,++inum),add(iv,iu,++inum),iu=iv;
}
dfs(1,0);
rebuild(1,0);
Tset::init(n);
for (int u=1;u<=n;u++)
for (int p=head[u];p;p=G[p].next)
if (!G[p].f)
Tset::Union(u,V);
for (int i=1,s;i<=n;i++)
if (Tset::Fat(i)==i && (s=Tset::Size(i))>2)
sum[i]=(ll)s*(s-1)/2-(s-1),tot+=sum[i];
for (int u=1;u<=n;u++)
for (int p=head[u];p;p=G[p].next)
if (G[p].f==2)
{
ll ttot=tot,len=1,tsum=Tset::Size(u);
ttot-=sum[Tset::Fat(u)];
for (int i=V;i!=u;i=nxt[i])
len++,tsum+=Tset::Size(i),ttot-=sum[Tset::Fat(i)];
ans+=(tsum*(tsum-1)/2-(tsum-1)-1)*len;
ans+=len*ttot;
}
printf("%lld\n",ans);
return 0;
}