模拟赛
抽象比赛,含金量最高的是题目背景?
好像还是连续的。。。
T1 Same Integers
题目背景
签到题,因为只有加操作,目标是将两个较小的数加成最大的。
根据差的奇偶判断能否加二得到,如果不能先加一调一下。(简单题,题解抽象一点也没事吧)
code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+5;
LL a[3],ans;
int main()
{
for(int i=0;i<3;i++) scanf("%lld",&a[i]);
sort(a,a+3);
int x=a[2]-a[0],y=a[2]-a[1];
if((x&1) && (y&1)) ans=(x-1>>1)+(y-1>>1)+1;
else if(x&1) ans=(y>>1)+(x+1>>1)+1;
else if(y&1) ans=(x>>1)+(y+1>>1)+1;
else ans=(x>>1)+(y>>1);
printf("%lld\n",ans);
return 0;
}
T2 Qpwoeirut and Vertices
首先要想到建立最小生成树,因为我们只在乎使某个连通块第一次被连通的边,后面再加边都可以忽略,所以最终建出的一定是一棵树。
然后考虑答案是什么,将边的编号赋成边权,那么使 \(u,v\) 连通的边权最大的边就是答案,也就是路径最大值。
使 \([l,r]\) 连通也很简单,就是使每两个相邻的节点连通,然后取区间最大值。
路径最大值可以用树剖 + ST 表,区间最值也用 \(ST\) 维护就好,发现是数据结构裸题。
正解是新科技:克鲁斯卡尔重构树。
不同于最小生成树,克鲁斯卡尔重构树是对于每一条边建一个虚点,点权等于原边权,虚点向原边的两个端点所在连通块的代表点连边。
因为加边按顺序,所以这样重构的树(森林)从根到叶子的权值一定是单调不上升的,那么使两点连通的最小权值就是重构树离他们最近的祖先的点权。
LCA + ST 表即可。
code(ST + ST)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int t;
int n,m,q;
struct K {int u,v,w;} k[N<<1];
inline bool cmp(const K &x,const K &y) {return x.w<y.w;}
int head[N],tot;
struct E {int u,v,w;} e[N<<1];
inline void add(int u,int v,int w) {e[++tot]={head[u],v,w}; head[u]=tot;}
struct BCJ
{
int fa[N];
inline void init() {for(int i=1;i<=n;i++) fa[i]=i;}
inline int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
} bcj;
int dfn[N],dep[N],son[N],sz[N],cnt,rk[N],fa[N],top[N],a[N];
void dfs1(int u,int f)
{
dep[u]=dep[f]+1; son[u]=-1; sz[u]=1; fa[u]=f;
for(int i=head[u];i;i=e[i].u)
{
int v=e[i].v;
if(v==f) continue;
a[v]=e[i].w;
dfs1(v,u);
sz[u]+=sz[v];
if(son[u]==-1||sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t; dfn[u]=++cnt; rk[cnt]=u;
if(son[u]==-1) return;
dfs2(son[u],t);
for(int i=head[u];i;i=e[i].u)
{
int v=e[i].v;
if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
}
}
struct ST1
{
int st[30][N];
inline void bui()
{
for(int i=1;i<=n;i++) st[0][i]=a[rk[i]];
for(int i=1;i<=25;i++)
for(int j=1;j+(1<<i)-1<=n;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
inline int que(int l,int r)
{
int k=__lg(r-l+1);
return max(st[k][l],st[k][r-(1<<k)+1]);
}
} st;
int Que(int x,int y)
{
int res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=max(res,st.que(dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(x==y) return res;
if(dep[x]>dep[y]) swap(x,y);
res=max(res,st.que(dfn[x]+1,dfn[y]));
return res;
}
struct ST2
{
int st[30][N];
inline void bui()
{
for(int i=1;i<n;i++) st[0][i]=Que(i,i+1);
for(int i=1;i<=25;i++)
for(int j=1;j+(1<<i)-1<n;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
inline int que(int l,int r)
{
int k=__lg(r-l+1);
return max(st[k][l],st[k][r-(1<<k)+1]);
}
} st2;
void init()
{
cnt=0; tot=0;
memset(head,0,sizeof(head));
}
int main()
{
// freopen("lagrange3.in","r",stdin);
// freopen("o1.out","w",stdout);
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d%d",&n,&m,&q); bcj.init();
for(int i=1;i<=m;i++)
{
int x,y; scanf("%d%d",&x,&y);
k[i]={x,y,i};
}
for(int i=1;i<=m;i++)
{
int fx=bcj.find(k[i].u),fy=bcj.find(k[i].v);
if(fx!=fy) bcj.fa[fx]=fy,add(k[i].u,k[i].v,k[i].w),add(k[i].v,k[i].u,k[i].w);
}
dfs1(1,0); dfs2(1,1);
st.bui(); st2.bui();
while(q--)
{
int x,y; scanf("%d%d",&x,&y);
if(x==y) printf("0\n");
else printf("%d\n",st2.que(x,y-1));
}
}
return 0;
}
code(重构树)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int t,q,n,m;
struct K {int u,v;} k[N];
int head[N],tot,num,w[N],fa[30][N],dep[N],a[N];
struct E {int u,v;} e[N<<1];
inline void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
struct BCJ
{
int fa[N];
void bui()
{
for(int i=1;i<=(n<<1);i++) fa[i]=i;
}
inline int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
} bcj;
void dfs(int u,int f)
{
dep[u]=dep[f]+1; fa[0][u]=f;
for(int i=1;i<=20;i++) fa[i][u]=fa[i-1][fa[i-1][u]];
for(int i=head[u];i;i=e[i].u)
{
int v=e[i].v; if(v==f) continue;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--) if(dep[fa[i][x]]>=dep[y]) x=fa[i][x];
if(x==y) return x;
for(int i=20;i>=0;i--) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
return fa[0][x];
}
struct ST
{
int st[20][N];
void bui()
{
for(int i=1;i<n;i++) st[0][i]=a[i];
for(int i=1;i<=20;i++)
for(int j=1;j<n;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
int que(int l,int r)
{
int k=__lg(r-l+1);
return max(st[k][l],st[k][r-(1<<k)+1]);
}
} st;
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&q); tot=0,num=n;
for(int i=1;i<=m;i++) scanf("%d%d",&k[i].u,&k[i].v);
for(int i=1;i<=n<<1;i++)
{
bcj.fa[i]=i; head[i]=0; dep[i]=0;
}
for(int i=1;i<=m;i++)
{
int fx=bcj.find(k[i].u),fy=bcj.find(k[i].v);
if(fx==fy) continue;
bcj.fa[fx]=bcj.fa[fy]=++num; w[num]=i;
add(num,fx); add(num,fy);
}
for(int i=num;i>=n+1;i--)
if(!dep[i]) dfs(i,0);
for(int i=1;i<n;i++)
{
int d=lca(i,i+1);
a[i]=w[d];
}
st.bui();
while(q--)
{
int l,r; scanf("%d%d",&l,&r);
if(l==r) printf("%d ",0);
else printf("%d ",st.que(l,r-1));
}
printf("\n");
}
return 0;
}