题解:CF2104G Modulo 3

题解

\(m\)缩点后的点数,那么最终的方案数就是 \(k^m\)

又因为答案对 \(3\) 取模,由费马小定理可知 \(k^m \equiv k^{m \mod 2} \pmod 3\),因此只需要求 \(m\) 的奇偶性。

基环森林每个连通块只有一个环,可以用并查集在出现环的时候将 \(m\) 异或上两点距离(的奇偶性)。用带权并查集就好了。

本题还带修改,那么对边做线段树分治就可以了。

代码

#include<bits/stdc++.h>
#define mk make_pair
#define For(i,il,ir) for(int i=(il);i<=(ir);++i)
#define Rof(i,ir,il) for(int i=(ir);i>=(il);--i)
using namespace std;
typedef pair<int,int> pii;
const int maxn=2e5+10;

int n,Q;
int k[maxn];
int pa[maxn],pt[maxn];

#define mid (l+r>>1)
pii opz;
int opx,opy;
vector<pii> tr[maxn<<2];
void update(int o,int l,int r){
    if(opx<=l && r<=opy){
        tr[o].push_back(opz);
        return;
    }
    if(opx<=mid) update(o<<1,l,mid);
    if(opy>mid) update(o<<1|1,mid+1,r);
}
void update(int l,int r,pii v){ opx=l,opy=r,opz=v;update(1,0,Q); }

int tp,ans;
pii st[maxn];
int fa[maxn],val[maxn],h[maxn];

int fd(int x,int &v){ v=0; while(x^fa[x]) v^=val[x],x=fa[x]; return x; }
void merge(int x,int y){
    int vx,vy;
    x=fd(x,vx),y=fd(y,vy);
    if(x==y) ans^=vx^vy;
    else{
        if(h[x]>h[y]) swap(x,y);
        st[++tp]=make_pair(x,h[x]==h[y]);
        fa[x]=y,val[x]=vx^vy^1,h[y]+=(h[x]==h[y]);
    }
}
void undo(int tar){
    while(tp>tar){
        int x=st[tp].first,d=st[tp].second;
        h[fa[x]]-=d,fa[x]=x,val[x]=0,tp--;
    }
}

int res[maxn];
void dfs(int o,int l,int r){
    int pretp=tp,preans=ans;
    for(pii c:tr[o]) merge(c.first,c.second);
    if(l==r) res[l]=ans;
    else dfs(o<<1,l,mid),dfs(o<<1|1,mid+1,r);
    undo(pretp); ans=preans;
}
signed main()
{
    scanf("%d%d",&n,&Q);
    For(i,1,n) scanf("%d",&pa[i]),fa[i]=i,h[i]=1;
    For(i,1,Q){
        int x,y;
        scanf("%d%d%d",&x,&y,&k[i]);
        update(pt[x],i-1,mk(x,pa[x]));
        pa[x]=y,pt[x]=i;
    }
    For(i,1,n) update(pt[i],Q,mk(i,pa[i]));

    ans=n&1;dfs(1,0,Q);
    For(i,1,Q) printf("%d\n",k[i]%3?(res[i]?k[i]%3:1):0);
    return 0;
}
posted @ 2025-05-08 21:13  wanggk  阅读(30)  评论(0)    收藏  举报