题解 树的路径变换问题 / [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;
}
posted @ 2022-07-20 15:12  Administrator-09  阅读(1)  评论(0编辑  收藏  举报