题意
给定一棵树,开始每条边都没有颜色
有m次操作,每次给定两个点对(a,b)(a,b)(a,b)(c,d)(c,d)(c,d),选择一个给两者的路径上的边染色
问是否存在一种选择方式,使得不存在被重复染色的边
分析
考虑这种二选一 的需要2-SAT解决
重点在于降低建图的复杂度
利用树链剖分和线段树实现路径染色
那么我们要求就是线段树上存在儿子祖先关系的点不能同时选择
这里用到了前缀和优化建图
最上方一行和最下方一行为辅助节点,这样保证了点数是O(nlog2n)O(nlog^2n)O(nlog2n)级别的,降低了复杂度
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,top[maxn],siz[maxn],son[maxn];
vector <int> G[maxn];
int m,seg[maxn];
int f[maxn],dep[maxn];
void dfs(int u,int fa)
{
siz[u]=1; dep[u]=dep[fa]+1; f[u]=fa;
for(auto to:G[u])
{
if(to==fa) continue;
dfs(to,u);
siz[u]+=siz[to];
if(siz[to]>siz[son[u]]) son[u]=to;
}
}
void ddfs(int u,int fa)
{
top[u]=fa; seg[u]=++seg[0];
if(son[u])
{
ddfs(son[u],fa);
for(auto to:G[u])
{
if(to==f[u] || to==son[u]) continue;
ddfs(to,to);
}
}
}
int cnt;
vector <int> tag[maxn<<2];
void modify(int now,int l,int r,int L,int R,int val)
{
if(l>=L && r<=R)
{
tag[now].push_back(val);
return;
}
int mid=l+r>>1;
if(L<=mid) modify(now<<1,l,mid,L,R,val);
if(mid<R) modify(now<<1|1,mid+1,r,L,R,val);
}
void add(int x,int y,int val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(1,2,n,seg[top[x]],seg[x],val);
x=f[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
if(seg[x]<seg[y]) modify(1,2,n,seg[x]+1,seg[y],val);
}
vector <int> T[maxn<<6];
void addedge(int x,int y)
{
T[x].push_back(y);
T[y^1].push_back(x^1);
}
void build(int now,int l,int r,int lst)
{
int L=++cnt,R=cnt+tag[now].size();
cnt+=tag[now].size();
if(L<R) addedge(R<<1|1,R-1<<1|1);
else if(lst) addedge(L<<1|1,lst<<1|1);
for(int i=0;i<tag[now].size();i++)
{
int id=tag[now][i];
if(i) addedge(L+i<<1|1,L+i-1<<1|1),addedge(L+i-1<<1,id^1);
else if(lst) addedge(L<<1|1,lst<<1|1),addedge(lst<<1,id^1);
addedge(id,L+i<<1);
}
if(l<r)
{
int mid=l+r>>1;
build(now<<1,l,mid,R);
build(now<<1|1,mid+1,r,R);
}
}
int dfn[maxn<<6],dfs_time,low[maxn<<6];
int st[maxn<<6],tp,color[maxn<<6],color_cnt;
void tarjan(int u)
{
st[++tp]=u; dfn[u]=low[u]=++dfs_time;
for(auto to:T[u])
{
if(!dfn[to])
{
tarjan(to);
low[u]=min(low[u],low[to]);
}
else if(!color[to])
low[u]=min(low[u],dfn[to]);
}
if(dfn[u]==low[u])
{
++color_cnt;
while(1)
{
color[st[tp]]=color_cnt;
tp--;
if(st[tp+1]==u) break;
}
}
}
int main()
{
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
scanf("%d",&n);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,0); ddfs(1,1);
scanf("%d",&m);
cnt=m;
for(int i=1;i<=m;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
add(a,b,i<<1); add(c,d,i<<1|1);
}
build(1,2,n,0);
for(int i=2;i<=(cnt<<1|1);i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=m;i++)
if(color[i<<1]==color[i<<1|1])
{
printf("NO");
return 0;
}
printf("YES\n");
for(int i=1;i<=m;i++)
printf("%d\n",color[i<<1]<color[i<<1|1]?1:2);
return 0;
}