[SP32952] ADAFTBLL - Ada and Football

Ada and Football の 传送门

前置:莫队

先用树上莫队转换成序列,修改则最后套个带修莫队。

假设新到一个点,它的权值已经出现了 \(apr\) 次。

那答案加上 \(apr\) 就行(前后贡献相减得出的)。

/* BORROWED_CODE */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
#define LL long long
int s[N],t,n,m,len,hd[N],lg[N],id,f[N][25],fi[N],la[N],d[N],a[N];
int qc,up_t;LL ans[N],res,cnt[N];bool vs[N];
struct edge{int v,nex;}e[N];void add_e(int u,int v){e[++id].v=v;e[id].nex=hd[u];hd[u]=id;}
struct query{int l,r,lc,tm,id;}q[N];
struct update{int p,v;}c[N];
bool cmp(query a,query b){
    if(a.l/len!=b.l/len)return a.l/len<b.l/len;
    if(a.r/len!=b.r/len)return a.r/len<b.r/len;
    return a.tm<b.tm;
}
void dfs(int u,int fa_p){
    fi[u]=++t;s[t]=u;
    d[u]=d[fa_p]+1;f[u][0]=fa_p;
    for(int i=1;i<=lg[d[u]];++i)f[u][i]=f[f[u][i-1]][i-1];
    for(int i=hd[u];i;i=e[i].nex)if(e[i].v!=fa_p)dfs(e[i].v,u);
    la[u]=++t;s[t]=u;
}
int lca(int x,int y){
    if(d[x]<d[y])swap(x,y);
    while(d[x]>d[y])x=f[x][lg[d[x]-d[y]]-1];
    if(x==y)return x;
    for(int i=lg[d[x]];i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
void upd(int x){
    vs[x]^=1;
    res-=cnt[a[x]]*(cnt[a[x]]-1ll)/2;
    cnt[a[x]]+=vs[x]?1:-1;
    res+=cnt[a[x]]*(cnt[a[x]]-1ll)/2;
}
int main(){
    scanf("%d%d",&n,&m);len=pow(n,2.0/3);for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int u,v,i=1;i<n;++i)scanf("%d%d",&u,&v),u++,v++,add_e(u,v),add_e(v,u);
    for(int i=1;i<N;++i)lg[i]=lg[i-1]+((1<<lg[i-1])==i);dfs(1,0);
    for(int op,x,y,i=1;i<=m;++i){
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)c[++up_t]={x+1,y};
        else{
            qc++;x++;y++;if(fi[x]>fi[y])swap(x,y);int z=lca(x,y);
            if(z!=x)q[qc]={la[x],fi[y],z,up_t,qc};
            else q[qc]={fi[x],fi[y],0,up_t,qc};
        }
    }
    m=qc;sort(q+1,q+m+1,cmp);
    for(int i=0,j=1,ct=0,k=1;k<=m;++k){
        int l=q[k].l,r=q[k].r,tm=q[k].tm,lc=q[k].lc;
        while(i<r)upd(s[++i]);
        while(i>r)upd(s[i--]);
        while(j>l)upd(s[--j]);
        while(j<l)upd(s[j++]);
        if(lc)upd(lc);
        while(ct<tm){
            ct++;int p=c[ct].p;
            if(vs[p]){
                res-=cnt[a[p]]*(cnt[a[p]]-1ll)/2;
                cnt[a[p]]--;
                res+=cnt[a[p]]*(cnt[a[p]]-1ll)/2;
                res-=cnt[c[ct].v]*(cnt[c[ct].v]-1ll)/2;
                cnt[c[ct].v]++;
                res+=cnt[c[ct].v]*(cnt[c[ct].v]-1ll)/2;
            }
            swap(a[p],c[ct].v);
        }
        while(ct>tm){
            int p=c[ct].p;
            if(vs[p]){
                res-=cnt[a[p]]*(cnt[a[p]]-1ll)/2;
                cnt[a[p]]--;
                res+=cnt[a[p]]*(cnt[a[p]]-1ll)/2;
                res-=cnt[c[ct].v]*(cnt[c[ct].v]-1ll)/2;
                cnt[c[ct].v]++;
                res+=cnt[c[ct].v]*(cnt[c[ct].v]-1ll)/2;
            }
            swap(a[p],c[ct].v);
            ct--;
        }
        ans[q[k].id]=res;
        if(lc)upd(lc);
    }
    for(int i=1;i<=m;++i)printf("%lld\n",ans[i]);
    return 0;
}
/* BORROWED_CODE */
posted @ 2025-02-06 22:44  SilverLi  阅读(14)  评论(0)    收藏  举报