题解 树的路径变换问题 / [AGC014E] Blue and Red Tree
传送门
[AGC014E] Blue and Red Tree
手玩一下
因为加一条红边的时候要求路径上蓝边都没动过
所以转化为链覆盖,每次找一条被覆盖次数为 1 的边删掉,再撤销对应的覆盖操作
可以对每条边维护所有覆盖其操作的异或和/hash 值之和来找到覆盖其的操作
复杂度 \(O(Tn\log^2 n)\),怎么连这个常也要卡
点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define ll long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ull pw[N];
vector<int> to[N];
pair<int, int> e[N];
const ull base=13131;
namespace task1{
unordered_map<ull, int> mp;
#define tl(p) tl[p]
#define tr(p) tr[p]
ull col[N<<2], tag2[N<<2];
int tl[N<<2], tr[N<<2], minn[N<<2], tag1[N<<2], mini[N<<2];
int id[N], rk[N], dep[N], siz[N], msiz[N], mson[N], top[N], back[N], fa[21][N], lg[N], tot;
inline void pushup(int p) {
minn[p]=min(minn[p<<1], minn[p<<1|1]);
mini[p]=minn[p]==minn[p<<1]?mini[p<<1]:mini[p<<1|1];
col[p]=minn[p]==minn[p<<1]?col[p<<1]:col[p<<1|1];
}
inline void spread(int p) {
if (tag1[p]) {
minn[p<<1]+=tag1[p]; tag1[p<<1]+=tag1[p];
minn[p<<1|1]+=tag1[p]; tag1[p<<1|1]+=tag1[p];
tag1[p]=0;
}
if (tag2[p]) {
col[p<<1]+=tag2[p]; tag2[p<<1]+=tag2[p];
col[p<<1|1]+=tag2[p]; tag2[p<<1|1]+=tag2[p];
tag2[p]=0;
}
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
col[p]=tag2[p]=minn[p]=tag1[p]=mini[p]=0;
if (l==r) {mini[p]=l; return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int l, int r, int val1, ull val2) {
if (l<=tl(p)&&r>=tr(p)) {minn[p]+=val1; tag1[p]+=val1; col[p]+=val2; tag2[p]+=val2; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, val1, val2);
if (r>mid) upd(p<<1|1, l, r, val1, val2);
pushup(p);
}
void dfs1(int u, int pa) {
siz[u]=1; msiz[u]=mson[u]=0;
for (int i=1; dep[u]>=1<<i; ++i)
fa[i][u]=fa[i-1][fa[i-1][u]];
for (auto& v:to[u]) if (v!=pa) {
dep[v]=dep[u]+1;
fa[0][v]=back[v]=u;
dfs1(v, u);
if (siz[v]>msiz[u]) msiz[u]=siz[v], mson[u]=v;
siz[u]+=siz[v];
}
}
void dfs2(int u, int fa, int t) {
top[u]=t;
rk[id[u]=++tot]=u;
if (!mson[u]) return;
dfs2(mson[u], u, t);
for (auto& v:to[u]) if (v!=fa&&v!=mson[u])
dfs2(v, u, v);
}
int lca(int a, int b) {
// if (dep[a]<dep[b]) swap(a, b);
// while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
// if (a==b) return a;
// for (int i=lg[dep[a]]-1; ~i; --i)
// if (fa[i][a]!=fa[i][b])
// a=fa[i][a], b=fa[i][b];
// return fa[0][a];
while (top[a]!=top[b]) {
if (dep[top[a]]<dep[top[b]]) swap(a, b);
a=fa[0][top[a]];
}
return dep[a]<dep[b]?a:b;
}
void upd(int u, int v, int val1, ull val2) {
while (top[u]!=top[v]) {
if (dep[top[u]]<dep[top[v]]) swap(u, v);
upd(1, id[top[u]], id[u], val1, val2);
u=back[top[u]];
}
if (dep[u]>dep[v]) swap(u, v);
upd(1, id[u], id[v], val1, val2);
}
void solve() {
mp.clear(); tot=0;
// memset(fa, 0, sizeof(fa));
for (int i=1; i<=n; ++i) mp[pw[i]]=i;
for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
dep[1]=1; dfs1(1, 0); dfs2(1, 0, 1); build(1, 1, tot);
for (int i=1; i<n; ++i) {
upd(e[i].fir, e[i].sec, 1, pw[i]);
int t=lca(e[i].fir, e[i].sec);
// cout<<"lca: "<<t<<endl;
upd(1, id[t], id[t], -1, -pw[i]);
}
for (int i=1; i<n; ++i) {
// cout<<"i: "<<i<<endl;
while (minn[1]==0) upd(1, mini[1], mini[1], INF, 0);
if (minn[1]>1) {puts("NO"); return ;}
int path=mp[col[1]];
// cout<<"path: "<<path<<endl;
assert(path);
upd(e[path].fir, e[path].sec, -1, -pw[path]);
int t=lca(e[path].fir, e[path].sec);
upd(1, id[t], id[t], 1, pw[path]);
}
puts("YES");
}
}
signed main()
{
freopen("tpc.in", "r", stdin);
freopen("tpc.out", "w", stdout);
while (n=read()) {
for (int i=1; i<=n; ++i) to[i].clear();
for (int i=1,u,v; i<n; ++i) {
u=read(); v=read();
to[u].pb(v); to[v].pb(u);
}
for (int i=1; i<n; ++i) e[i]={read(), read()};
pw[0]=1;
for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
task1::solve();
}
puts("0");
return 0;
}