肯定是树剖做
分析一下3种操作
1:翻转一条链,直接翻
2:翻转与一条链相邻的边
可以发现,与一条链相邻的边中,是与父亲相连的边只有顶端的那一条,这一条可以直接暴力翻转,然后我们重新定义与链相连的边是链上每个点和儿子相邻的边中不在链上的边
考虑链上每个点和儿子的边,按轻重分类,对于轻边,我们也不需要考虑他们,因为查询时遇到的轻边是log条的,我们可以对这个点打标记,查询时暴力查询每条轻边父亲的标记
于是我们只需要考虑链上每个点与孩子的边中的重边
一次操作会遇到log条重链,每条重链中,只有截下的那段的尾端可能修改他的重儿子,其他点的重儿子都在这条链上,每条重链暴力改就行了
3:查询一条链上黑边个数
结合一下操作二和树剖查
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 210000;
int n,m;
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
int siz[maxn],son[maxn],fa[maxn],dep[maxn],w[maxn],z,top[maxn];
void dfs(const int x)
{
siz[x]=1; son[x]=0;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa[x])
{
fa[y]=x,dep[y]=dep[x]+1;
dfs(y);
if(siz[son[x]]<=siz[y]) son[x]=y;
siz[x]+=siz[y];
}
}
void build(const int x,const int tp)
{
w[x]=++z; top[x]=tp;
if(son[x]) build(son[x],tp);
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa[x]&&y!=son[x])
build(y,y);
}
struct segment
{
int s1[maxn<<2],s2[maxn<<2];
int flag[maxn<<2];
void pushup(const int x){s1[x]=s1[x<<1]+s1[x<<1|1],s2[x]=s2[x<<1]+s2[x<<1|1];}
void pushdown(const int x)
{
if(!flag[x]) return;
flag[x]^=1;
int lc=x<<1,rc=lc|1;
swap(s1[lc],s2[lc]); flag[lc]^=1;
swap(s1[rc],s2[rc]); flag[rc]^=1;
}
void build(const int x,const int l,const int r)
{
s1[x]=r-l+1,s2[x]=0,flag[x]=0;
if(l==r) return;
int mid=l+r>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
}
int lx,rx;
void rev(const int x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(lx<=l&&r<=rx) { swap(s1[x],s2[x]);flag[x]^=1;return; }
pushdown(x);
int mid=l+r>>1;
rev(x<<1,l,mid); rev(x<<1|1,mid+1,r);
pushup(x);
}
int que(const int x,const int l,const int r)
{
if(rx<l||r<lx) return 0;
if(lx<=l&&r<=rx) return s2[x];
int mid=l+r>>1;
pushdown(x);
return que(x<<1,l,mid)+que(x<<1|1,mid+1,r);
}
int pc[maxn];
void clear(){for(int i=0;i<=n;i++) pc[i]=0;}
void add(int x){for(;x<=n;x+=lowbit(x))pc[x]++;return;}
int qp(int x){int re=0;for(;x;x-=lowbit(x))re+=pc[x];return re;}
}seg;
void reve(int x,int y)
{
int f1=top[x],f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
seg.lx=w[f1],seg.rx=w[x],seg.rev(1,1,z);
x=fa[f1],f1=top[x];
}
if(x==y)return;
if(dep[x]>dep[y]) swap(x,y);
seg.lx=w[x]+1,seg.rx=w[y],seg.rev(1,1,z);
}
int ti[maxn],nowt;
void revp(int x,int y)
{
if(x==y)
{
seg.lx=seg.rx=w[x],seg.rev(1,1,z);
if(son[x]) seg.lx=seg.rx=w[x]+1,seg.rev(1,1,z);
seg.add(w[x]); seg.add(w[x]+1);
return;
}
nowt++;
int tx=x,ty=y;
int f1=top[x],f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
seg.add(w[f1]),seg.add(w[x]+1);
seg.lx=seg.rx=w[f1],seg.rev(1,1,z);
x=fa[f1],f1=top[x];
if(son[x]&&ti[w[son[x]]]!=nowt&&!(f2==f1&&dep[y]>dep[x]))
ti[w[son[x]]]=nowt,seg.lx=seg.rx=w[son[x]],seg.rev(1,1,z);
}
if(dep[x]>dep[y]) swap(x,y);
seg.add(w[x]),seg.add(w[y]+1);
seg.lx=seg.rx=w[x],seg.rev(1,1,z);
if(son[tx]&&x!=tx) seg.lx=seg.rx=w[tx]+1,seg.rev(1,1,z);
if(son[ty]&&x!=ty) seg.lx=seg.rx=w[ty]+1,seg.rev(1,1,z);
}
int query(int x,int y)
{
int f1=top[x],f2=top[y];
int ans=0;
while(f1!=f2)
{
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
seg.lx=w[f1],seg.rx=w[x]; ans+=seg.que(1,1,z);
seg.lx=seg.rx=w[f1]; int tmp=seg.que(1,1,z);
if(seg.qp(w[fa[f1]])&1) ans=ans-tmp+(!tmp);
x=fa[f1],f1=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
if(x!=y)
{
seg.lx=w[x]+1,seg.rx=w[y],ans+=seg.que(1,1,z);
}
return ans;
}
int main()
{
int tcase; read(tcase);
while(tcase--)
{
read(n);
len=0; for(int i=1;i<=n;i++) fir[i]=0;
for(int i=1;i<n;i++)
{
int x,y; read(x); read(y);
ins(x,y); ins(y,x);
}
dep[1]=1; dfs(1);
z=0; build(1,1);
seg.build(1,1,z); seg.clear();
read(m);
while(m--)
{
int ti,x,y; read(ti); read(x); read(y);
if(ti==1) reve(x,y);
if(ti==2)
revp(x,y);
if(ti==3)
printf("%d\n",query(x,y));
}
}
return 0;
}