新年快乐各位
懒得写学期总结
不会起标题了
铁人两项
昨晚今早做的,补一下题解
就是让你求一个图有多少个三元组
那么,当一个点到另一个点经过点双时,点双里的任何一点都可以作为中转点
所以缩点
但缩完点点双内部就不好处理了
所以给他建成圆方树
圆方树可以做到把简单无向图转换为我们熟悉的树结构,从而进行一些树上的操作,所以我们在遇到这种图时会想到圆方树
把方点的权值设为点双的点的个数
就变成了
求两个圆点之间的点权和
容斥掉两个端点和交界处的点(割点)
所以给圆点权值附上 -1(连接几个点双的就是割点)
一开始我用了一个非常麻烦的做法……
其实就先算子树之间的贡献,再算祖先和子树的贡献就行
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+6;
int n,m,head[N],cnt,head1[N],cnt1,ans;
struct node{int to,nxt;}e[N],e1[N];
void add(int u,int v){e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void add1(int u,int v){e1[++cnt1].to=v;e1[cnt1].nxt=head1[u];head1[u]=cnt1;
}
int dfn[N],low[N],tim,st[N],top,tot,val[N],siz[N];
bool vis[N];
int subn=0;
void tarjan(int u,int fa){subn++;st[++top]=u;dfn[u]=low[u]=++tim;for(int i=head[u];i;i=e[i].nxt){int v=e[i].to;if(v==fa)continue;if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]){//割点是>= 割边是>++tot;int va=0;for(int p=0;p!=v;top--){va++;p=st[top];val[p]=-1;add1(tot,p),add1(p,tot);// cout<<tot<<" "<<p<<endl;}val[u]=-1;add1(tot,u),add1(u,tot);//cout<<tot<<" "<<u<<endl;val[tot]=va+1;}}else low[u]=min(low[u],dfn[v]);}
}void dfs(int u,int f){siz[u]=(u<=n);for(int i=head1[u];i;i=e1[i].nxt){int v=e1[i].to;if(v==f)continue;dfs(v,u);ans+=val[u]*siz[v]*siz[u];siz[u]+=siz[v];// cout<<u<<" "<<val[u]*siz[v]*(siz[rt]-siz[v]-(u<=n))<<endl;}ans+=val[u]*siz[u]*(subn-siz[u]);
}
signed main(){cin>>n>>m;tot=n;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}for(int i=1;i<=n;i++){if(!dfn[i]){subn=0;tarjan(i,0),dfs(i,0);}}cout<<ans*2;return 0;
}
诺宇找到了她的小说本
(如果在某小说网上找到了诺宇|诺麟瑜宇|冷瑜麟,那就是我)
(冷瑜麟是诺宇小说的主人公,并客串了数本小说,至于为啥叫这名字……)
(离谱的是诺宇到现在都没想好冷瑜麟是男是女)