题目链接
(已被hack)
Totori’s Switching Game(全局最小割)
题意:
给一个无向图,可能有重边,问是否可以找到边不相同的 个生成树。
思路:
比赛的时候直接判断了所有点的度,实际上是因为数据太水过了。
后来才知道这题是全局最小割的板题。全局最小割可以求出使得无向图不连通的最小代价,那么我们将每一条边的权值设为1,那么如果当前的全局最小割为
,如果它等于
,就说明要断开
条边才能使得图不连通,也就是说这张图存在
个生成树。
那么就套一下板子即可。
代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=400;
int tu[N][N],dis[N];
bool vis[N],d[N];
int StoerWagner(int n)//顶点数
{
int p=n,ans=inf,Max,t,s,k,i;
memset(d,0,sizeof(d));
while (--p>0)
{
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
i=1;
while (d[i]) i++;
vis[i]=1;
for (int j=1;j<=n;j++)
if (!d[j] && !vis[j])
dis[j]=tu[i][j];
t=s=i;
for (;i<=n;i++)
{
Max=0;
for (int j=1;j<=N;j++)
if (!d[j] && !vis[j] && Max<dis[j])
Max=dis[k=j];
if (!Max) break;
vis[k]=1;
for (int j=1;j<=N;j++)
if (!d[j] && !vis[j])
dis[j]+=tu[k][j];
s=t;
t=k;
}
if (ans>dis[t]) ans=dis[t];
d[t]=1;
for (int j=1;j<=N;j++)
if (!d[j])
{
tu[s][j]+=tu[t][j];
tu[j][s]+=tu[j][t];
}
}
return ans;
}
int n,m,K;
int T;
int main(){
scanf("%d",&T);
while(T--){
memset(tu,0,sizeof(tu));
scanf("%d%d%d",&n,&m,&K);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
tu[u][v]++;tu[v][u]++;
}
if(StoerWagner(n)>=K){
puts("Yes");
}else puts("No");
}
}
题目链接
wls 的树(树链剖分+主席树+并查集)
题意:
给定一颗树,有 次操作,两种类型操作,第一种 ,将以 为根的子树重新排列按照编号从大到小变成一条链,编号最大的做为根。第二种 ,查询 到 的路径上经过几条边。
思路:
对于第一种操作,可以用并查集维护,将
的子树的点都指向
,在每次操作时观察该点是否已经使用过第一种操作,如果使用过,就将它指向
,那么它的子树必然也指向
,这样平均每一个点只用操作一次。
对于第二种操作,我们现观察
和
是否在同一个集合内,如果是,那么答案就是他们的差值。如果不是,那么假设在
和
集合中,我们先计算出
到
的距离
,再在线段树中算出在
子树中大于
的个数,在
子树中大于
的个数,相当于从
,把三个距离加起来即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int>e[N];
//树剖
int tot[N],son[N],deep[N],fa[N];
int dfs1(int u,int f,int dep){
tot[u]=1;fa[u]=f;deep[u]=dep;
int pd=-1;
for(int v:e[u]){
if(v==f)continue;
tot[u]+=dfs1(v,u,dep+1);
if(tot[v]>pd)pd=tot[v],son[u]=v;
}
return tot[u];
}
int idx[N],top[N],id[N],cnt;
void dfs2(int u,int f){
idx[u]=++cnt,id[cnt]=u;
top[u]=f;
if(!son[u])return ;
dfs2(son[u],f);
for(int v:e[u]){
if(!idx[v])dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
//
//主席树
struct zx_tree{
int ls[N*50],rs[N*50],rt[N*50],tot,sum[N*50];
inline void update(int &root,int pre,int l,int r,int pos){
root=++tot;ls[root]=ls[pre],rs[root]=rs[pre],sum[root]=sum[pre]+1;
if(l==r)return ;
int mid=(l+r)/2;
if(pos<=mid)update(ls[root],ls[pre],l,mid,pos);
else update(rs[root],rs[pre],mid+1,r,pos);
}
inline int query(int root,int pre,int l,int r,int k){
if(l>k)return sum[root]-sum[pre];
int ans=0;
int mid=(l+r)/2;
if(k<mid)ans+=query(ls[root],ls[pre],l,mid,k);
if(k<r)ans+=query(rs[root],rs[pre],mid+1,r,k);
return ans;
}
}T;
//
//并查集
int Fa[N];
int fi(int x){
if(x==Fa[x])return x;
return Fa[x]=fi(Fa[x]);
}
//
int TT,n,m;
void init(){
for(int i=1;i<=n;i++)Fa[i]=0,idx[i]=0,son[i]=0;
for(int i=1;i<=n;i++)e[i].clear();
cnt=0;deep[0]=0;
for(int i=1;i<=T.tot;i++)T.rt[i]=0;
T.tot=0;
}
void dfs(int u,int x){
if(Fa[u]!=0){
Fa[fi(u)]=x;
return ;
}
else{
Fa[u]=x;
for(int v:e[u]){
if(v==fa[u])continue;
dfs(v,x);
}
}
}
int cl2(int x,int y){
int f1=x,f2=y;
int d1=0,d2=0;
if(Fa[x]){
f1=fi(x);
d1=T.query(T.rt[idx[f1]+tot[f1]-1],T.rt[idx[f1]-1],1,n,x);
}
if(Fa[y]){
f2=fi(y);
d2=T.query(T.rt[idx[f2]+tot[f2]-1],T.rt[idx[f2]-1],1,n,y);
}
if(f1==f2){
return abs(d1-d2);
}
int Lca=lca(f1,f2);
int dis=deep[f1]+deep[f2]-2*deep[Lca];
return dis+d1+d2;
}
int main()
{
//freopen("txt.in","r",stdin);
scanf("%d",&TT);
while(TT--){
scanf("%d",&n);
init();
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e[u].push_back(v);e[v].push_back(u);
}
dfs1(1,0,1),dfs2(1,0);
for(int i=1;i<=cnt;i++)T.update(T.rt[i],T.rt[i-1],1,n,id[i]);
scanf("%d",&m);
int op,x,y;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d",&x);
if(Fa[x]==0)dfs(x,x);
}
else {
scanf("%d%d",&x,&y);
printf("%d\n",cl2(x,y));
}
}
}
}