8.25NOIP Day10模拟赛

T1

赛时一直在做容斥然后卡了一万年才过。

注意到每个字母是独立的,所以可以分开处理

发现可以选择一个点使得最大深度不超过2,那么我们可以维护从每一个点连续长度为1和2的链数量,然后枚举中心点跑出答案

#include<bits/stdc++.h>
#define mod 998244353
#define int long long 
#define N 100005
using namespace std;
struct Ty{int u,v;}x[N];
vector<int>y[N];
int dpc,dpf,dis[N],node[N],summ=0;
signed main(){
    int n,m;
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++)scanf("%lld%lld",&x[i].u,&x[i].v);
    for(int i=1;i<=n;i++)node[i]=n-1;
    for(int i=1;i<=m;i++){
        node[x[i].u]--;
        node[x[i].v]--;
        y[x[i].u].push_back(x[i].v);
        y[x[i].v].push_back(x[i].u);
    }
    for(int i=1;i<=n;i++)summ=(summ+node[i])%mod;
    for(int i=1;i<=n;i++){
        dis[i]=(summ-node[i]+mod)%mod;
        for(int j=0;j<y[i].size();j++)dis[i]=(dis[i]-node[y[i][j]]+mod)%mod;
    }
    for(int i=1;i<=n;i++){
        dpc=(dpc+dis[i]*node[i]%mod)%mod;
        dpf=(dpf+dis[i]*node[i]%mod*node[i]%mod)%mod;
    }
    printf("%lld\n",dpc*dpc%mod*dpf%mod);
    return 0;
}

T2

力大砖飞。

注意到消去的点数总和是 \(O(n)\) 级别的,同时每个节点的父节点不变,考虑使用并查集暴力维护合并

这里需要找LCA,有个trick是从u,v两个点交换着暴力往上跳打标记,碰到第一个打过标记的就是LCA,由于跳过的点都会被合并掉,所以不影响复杂度

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
vector<int>y[N];
int x[N],fa[N],vis[N];
int findd(int u){
    if(x[u]==u)return u;
    return x[u]=findd(x[u]);
}
void dfs(int u,int Fa){
    fa[u]=Fa;
    for(int i=0;i<y[u].size();i++)if(y[u][i]!=Fa)dfs(y[u][i],u);
    return;
}
int update(int u,int v,int w){
    int a=u,b=v,p=0;
    while(1){
        if(vis[a]==w&&a!=0){
            p=a;
            break;
        }
        vis[a]=w;
        a=findd(fa[a]);
        swap(a,b);
    }
    a=u;
    b=v;
    int now=0;
    while(a!=p){
        x[a]=w;
        now++;
        a=findd(fa[a]);
    }
    while(b!=p){
        x[b]=w;
        now++;
        b=findd(fa[b]);
    }
    x[p]=w;
    fa[w]=fa[p];
    return now;
}
signed main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        y[u].push_back(v);
        y[v].push_back(u);
    }
    for(int i=1;i<=n+m;i++)x[i]=i;
    dfs(1,0);
    int ans=n;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        ans-=update(u,v,n+i);
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2025-08-25 10:50  Igunareo  阅读(13)  评论(0)    收藏  举报