模拟赛
抽象比赛,含金量最高的是题目背景?
好像还是连续的。。。
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;
}