题解:
这一道题目和模板有不同的地方就是在于可以修改只有一条边和i相邻
于是我们还要记录与这个点相邻的点有没有改变
代码:
#pragma GCC optimize(2) #include<bits/stdc++.h> const int N=400005; using namespace std; int fi[N],zz[N],ne[N],deep[N],fa[N],size[N],son[N],top[N]; int x,y,opt,pos[N],q[N],cnt,h[N],tot,n,m,T; struct data { int w,b,delta,rev; }tr[N*4]; void add(int x,int y) { ne[++tot]=fi[x]; fi[x]=tot; zz[tot]=y; } void dfs(int x,int f) { size[x]=1; son[x]=0; deep[x]=deep[f]+1; for (int i=fi[x];i;i=ne[i]) { if (zz[i]==f) continue; fa[zz[i]]=x; dfs(zz[i],x); size[x]+=size[zz[i]]; if (size[zz[i]]>size[son[x]]) son[x]=zz[i]; } } void dfs1(int x,int y) { pos[x]=++cnt;q[cnt]=x;top[x]=y; if (!son[x])return; dfs1(son[x],y); for (int i=fi[x];i;i=ne[i]) if (zz[i]!=son[x]&&zz[i]!=fa[x]) dfs1(zz[i],zz[i]); } void update(data &now,data l,data r) { now.w=l.w+r.w; now.b=l.b+r.b; } void clear(int now) { tr[now].b=tr[now].w=tr[now].rev=tr[now].delta=0; } void build(int now,int l,int r) { clear(now); if (l==r) { tr[now].b=0; if (l!=1) tr[now].w=1; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(tr[now],tr[now<<1],tr[now<<1|1]); } void change(int now) { swap(tr[now].w,tr[now].b); tr[now].delta^=1; } void pushdown(int now) { if (tr[now].delta) { change(now<<1); change(now<<1|1); tr[now].delta=0; } if (tr[now].rev) { tr[now<<1].rev^=1; tr[now<<1|1].rev^=1; tr[now].rev=0; } } data query(int now,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) return tr[now]; pushdown(now); int mid=(l+r)/2;data ans;int pd=0; if (ll<=mid) ans=query(now<<1,l,mid,ll,rr),pd=1; if (rr>mid) { if (pd) update(ans,ans,query(now<<1|1,mid+1,r,ll,rr)); else ans=query(now<<1|1,mid+1,r,ll,rr); } return ans; } void qjchange(int now,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) { change(now); return; } int mid=(l+r)/2; pushdown(now); if (ll<=mid) qjchange(now<<1,l,mid,ll,rr); if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr); update(tr[now],tr[now<<1],tr[now<<1|1]); } void reverse(int now,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) { tr[now].rev^=1; return; } pushdown(now); int mid=(l+r)/2; if (ll<=mid) reverse(now<<1,l,mid,ll,rr); if (rr>mid) reverse(now<<1|1,mid+1,r,ll,rr); update(tr[now],tr[now<<1],tr[now<<1|1]); } void solve(int x,int y) { while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); qjchange(1,1,n,pos[top[x]],pos[x]); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x==y) return; qjchange(1,1,n,pos[x]+1,pos[y]); } void paint(int x,int y) { bool pd=false; int t=0; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); reverse(1,1,n,pos[top[x]],pos[x]); if (son[x]) qjchange(1,1,n,pos[son[x]],pos[son[x]]); qjchange(1,1,n,pos[top[x]],pos[top[x]]); t=top[x]; x=fa[top[x]]; h[x]=t; } if (deep[x]>deep[y]) swap(x,y); reverse(1,1,n,pos[x],pos[y]); qjchange(1,1,n,pos[x],pos[x]); if (son[y]) qjchange(1,1,n,pos[son[y]],pos[son[y]]); } int find(int now,int l,int r,int x) { if (x==0) return 0; if (l==r) return tr[now].rev; int mid=(l+r)/2; pushdown(now); if (x<=mid) return find(now<<1,l,mid,x); else return find(now<<1|1,mid+1,r,x); } int calc(int x,int y) { int ans=0; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); data t=query(1,1,n,pos[top[x]],pos[x]); data t1=query(1,1,n,pos[top[x]],pos[top[x]]); int k=find(1,1,n,pos[fa[top[x]]]); if (t1.b==1&&k) t.b--; if (t1.w==1&&k) t.b++; ans+=t.b; x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x==y) return ans; data t=query(1,1,n,pos[x]+1,pos[y]); return ans+t.b; } int main() { scanf("%d",&T); while (T--) { tot=cnt=0; memset(fi,0,sizeof fi); scanf("%d",&n); for (int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(1,0);dfs1(1,1);build(1,1,n); scanf("%d",&m); while (m--) { scanf("%d%d%d",&opt,&x,&y); if (opt==1) solve(x,y); if (opt==2) paint(x,y); if (opt==3) printf("%d ",calc(x,y)); } } return 0; }