2025多校冲刺省选模拟赛8
\(T1\) A. 波斯菊 \(10pts/10pts\)
-
每个连通块内以关键点为起点的最长路径 \(d_{i}\) 相互独立,有 \(2n-2k-\sum\limits_{i=1}^{k}d_{k}\) 即为所求。
-
观察到可以直接钦定每个关键点距离其最远的点的是哪个点,这样的话就只需要任意两个路径不相交就能保证一定存在一种划分方案合法。
-
设 \(f_{x,0/1/2}\) 分别表示以 \(x\) 为根的子树内只有一个起点在往上走/只有一个终点在往上走(不一定要被匹配到)/没有点在往上走的答案。
-
转移时考虑从两棵子树内的节点转移而来,特殊处理关键点处的转移。
点击查看代码
struct node {ll nxt,to; }e[1000010]; ll head[500010],vis[500010],f[3][500010],cnt=0; void add(ll u,ll v) {cnt++;e[cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt; } void dfs(ll x,ll fa) {ll maxx,sum=0,u=-0x3f3f3f3f3f3f3f3f,v=-0x3f3f3f3f3f3f3f3f;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa){dfs(e[i].to,x);sum+=max(f[1][e[i].to],f[2][e[i].to]);}}if(vis[x]==1){f[1][x]=sum;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa){f[0][x]=max(f[0][x],sum-max(f[1][e[i].to],f[2][e[i].to])+f[0][e[i].to]);f[2][x]=max(f[2][x],sum-max(f[1][e[i].to],f[2][e[i].to])+f[0][e[i].to]);}} }else{f[0][x]=1;f[1][x]=-0x3f3f3f3f3f3f3f3f;f[2][x]=sum;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa){maxx=max(f[1][e[i].to],f[2][e[i].to]);f[0][x]=max(f[0][x],sum-maxx+f[0][e[i].to]+1);f[1][x]=max(f[1][x],sum-maxx+f[1][e[i].to]+1);f[2][x]=max({f[2][x],sum-maxx+f[1][e[i].to]+1+u,sum-maxx+f[0][e[i].to]+1+v});u=max(u,f[0][e[i].to]-maxx); v=max(v,f[1][e[i].to]-maxx);}}} } int main() { #define Isaac #ifdef Isaacfreopen("coreopsis.in","r",stdin);freopen("coreopsis.out","w",stdout); #endifll n,k,x,u,v,i;cin>>n>>k;for(i=1;i<=k;i++){cin>>x;vis[x]=1;}for(i=1;i<=n-1;i++){cin>>u>>v;add(u,v); add(v,u);}dfs(x,0);cout<<2*n-2*k-max({f[0][x],f[1][x],f[2][x]})<<endl;return 0; }
\(T2\) B. 芦荀花 \(60pts/60pts\)
-
连通块数 \(-1\) 即为所求。
-
部分分
- \(50 \sim 60pts\)
-
连通块数等于边数减点数,考虑差的来源是由于连通块顶部的点导致的。稍微卡卡常,时间复杂度为 \(O(nm)\) 。
点击查看代码
int fa[500010],dfn[500010],pos[500010],vis[500010],tot=0; pair<int,int>a[500010]; vector<int>e[500010]; void add(int u,int v) {e[u].push_back(v); } void dfs(int x,int father) {tot++; dfn[x]=tot; pos[tot]=x;fa[x]=father;for(int i=0;i<e[x].size();i++){if(e[x][i]!=father) dfs(e[x][i],x);} } int main() { #define Isaac #ifdef Isaacfreopen("fructus.in","r",stdin);freopen("fructus.out","w",stdout); #endifint n,m,b,ans=0,u,v,i,j,k;scanf("%d%d%d",&n,&m,&b);for(i=1;i<=n-1;i++){scanf("%d%d",&u,&v);add(u,v); add(v,u);}for(i=1;i<=n;i++) sort(e[i].begin(),e[i].end());dfs(1,0);for(;m>=1;m--){scanf("%d",&k); ans*=b;for(i=1;i<=k;i++){scanf("%d%d",&a[i].first,&a[i].second);a[i].first^=ans; a[i].second^=ans;for(j=a[i].first;j<=a[i].second;j++) vis[pos[j]]=1;}ans=-1;for(i=k;i>=1;i--) {for(j=a[i].second;j>=a[i].first;j--) {vis[pos[j]]=0;ans+=(vis[fa[pos[j]]]==0);}}printf("%d\n",ans);}return 0; }
-
若连通块内部已经连通是容易处理的,取 \(\operatorname{LCA}\) 判断即可。按照 \(DSF\) 序记录叶子节点后划分成若干条链后时间复杂度瓶颈不在判断某个点是否被选中,即使优化也没有什么大的用处,时间复杂度为 \(O(mt)\) ,其中 \(t\) 为叶子个数。
- 貌似把拆分成链转换成拆分成子树就可以通过 \(Subtest7,k=1\) 的测试点。
点击查看代码
int fa[500010],dfn[500010],vis[500010],tot=0; pair<int,int>a[500010]; vector<int>e[500010],leaf; void add(int u,int v) {e[u].push_back(v); } void dfs(int x,int father) {int flag=0;tot++; dfn[x]=tot;fa[tot]=dfn[father];for(int i=0;i<e[x].size();i++){if(e[x][i]!=father) {flag=1;dfs(e[x][i],x);}}if(flag==0) leaf.push_back(dfn[x]); } int main() { #define Isaac #ifdef Isaacfreopen("fructus.in","r",stdin);freopen("fructus.out","w",stdout); #endifint n,m,b,ans=0,tmp,u,v,i,j,k;scanf("%d%d%d",&n,&m,&b);for(i=1;i<=n-1;i++){scanf("%d%d",&u,&v);add(u,v); add(v,u);}for(i=1;i<=n;i++) sort(e[i].begin(),e[i].end());dfs(1,0);for(;m>=1;m--){scanf("%d",&tmp); k=1; ans*=b;for(i=1;i<=tmp;i++){scanf("%d%d",&a[i].first,&a[i].second);a[i].first^=ans; a[i].second^=ans;for(j=a[i].first;j<=a[i].second;j++) vis[j]=1;if(i>=2){if(a[i].first==a[k].second+1) a[k].second=a[i].second;else{k++;a[k]=a[i];}}}ans=-1;u=lower_bound(leaf.begin(),leaf.end(),a[k].first)-leaf.begin();v=upper_bound(leaf.begin(),leaf.end(),a[k].second)-leaf.begin()-1;for(i=k;i>=1;i--){while(leaf[u-1]>=a[i].first&&u-1>=0) u--;while(leaf[v]>a[i].second&&v>=0) v--;if(u>v) ans+=(vis[fa[a[i].first]]==0);else {for(j=u;j<=v;j++){ans+=((vis[fa[(j==u)?a[i].first:(leaf[j-1]+1)]])==0);}if(a[i].second!=leaf[v]) ans+=(vis[fa[leaf[v]+1]]==0);}for(j=a[i].first;j<=a[i].second;j++) vis[j]=0;}printf("%d\n",ans);}return 0; }
-
- \(50 \sim 60pts\)
-
正解
\(T3\) C. 豆蔻花 \(0pts/0pts\)
总结
- \(T1\) 读假题了,以为同时可以移动 \(k\) 个石子,最后的式子多一个连通块大小,直接假了。
- 没想到 \(T2\) 主席树维护二维数点的暴力做法。