题解 数颜色

传送门

发现连通块个数 = 被点亮点数 - 被点亮边数
赛时从这里开始思路就僵化了
只会各种试图优化点集,边集求交
其实存在另一个转化:如果将一条路径的边下放到点上,则只有 lca 是未被覆盖的
又发现一个连通块中有且仅有一个这样的未被覆盖的 lca
于是对这个东西计数
枚举路径计算它前面和后面第一次覆盖它的位置 \(left_i, right_i\)
考虑 lca 重合的情况,钦定 left 不包含重复的 lca
于是这两个东西可以树剖求出来
然后对询问右端点扫描线即可
一个机器人的贡献是在 \(i\) 时让 \([left_i+1, i]\) +1,在 \(right_i\) 时让 \([left_i+1, i]\) -1
复杂度 \(O(n\log^2 n)\),一个优化是 lct 代替树剖可以做到 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int 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, m, q;
int x[N], y[N];
pair<int, int> g[N];
int head[N], dep[N], anc[N], back_edge[N], ecnt=1;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}

void dfs1(int u, int fa) {
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (v==fa) continue;
		dep[v]=dep[u]+1;
		anc[v]=u; back_edge[v]=i>>1;
		dfs1(v, u);
	}
}

namespace force{
	int path[N], len;
	bool vis_p[N], vis_e[N];
	void dfs1(int u, int fa) {
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dep[v]=dep[u]+1;
			anc[v]=u; back_edge[v]=i;
			dfs1(v, u);
		}
	}
	void get_path(int u, int v) {
		vis_p[u]=vis_p[v]=1;
		while (u!=v) {
			if (dep[u]<dep[v]) swap(u, v);
			vis_e[back_edge[u]]=1;
			vis_p[u=anc[u]]=1;
		}
	}
	void dfs2(int u) {
		vis_p[u]=0;
		for (int i=head[u],v; ~i; i=e[i].next) if (vis_e[i]) {
			v = e[i].to;
			if (vis_p[v]) dfs2(v);
		}
	}
	void solve() {
		for (int i=1; i<n; ++i) add(g[i].fir, g[i].sec), add(g[i].sec, g[i].fir);
		dep[1]=1; dfs1(1, 0);
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			memset(vis_p, 0, sizeof(vis_p));
			memset(vis_e, 0, sizeof(vis_e));
			for (int j=l; j<=r; ++j) get_path(x[j], y[j]);
			int ans=0;
			for (int j=1; j<=n; ++j) if (vis_p[j]) ++ans, dfs2(j);
			printf("%d\n", ans);
		}
	}
}

namespace task1{
	const int blc=1010;
	int tl[blc<<2], tr[blc<<2], tot;
	bitset<blc> dat_p[blc<<2], dat_e[blc<<2], pre_p[blc], pre_e[blc];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define datp(p) dat_p[p]
	#define date(p) dat_e[p]
	void get_path(int u, int v, int id) {
		pre_p[id][u]=1; pre_p[id][v]=1;
		while (u!=v) {
			if (dep[u]<dep[v]) swap(u, v);
			pre_e[id][back_edge[u]]=1;
			pre_p[id][u=anc[u]]=1;
		}
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {datp(p)=pre_p[l]; date(p)=pre_e[l]; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		datp(p)=datp(p<<1)|datp(p<<1|1);
		date(p)=date(p<<1)|date(p<<1|1);
	}
	void query(int p, int l, int r, bitset<blc>& ansp, bitset<blc>& anse) {
		if (l<=tl(p)&&r>=tr(p)) {ansp|=datp(p); anse|=date(p); return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) query(p<<1, l, r, ansp, anse);
		if (r>mid) query(p<<1|1, l, r, ansp, anse);
	}
	void solve() {
		int tot=n;
		for (int i=1; i<n; ++i) add(g[i].fir, g[i].sec), add(g[i].sec, g[i].fir);
		dep[1]=1; dfs1(1, 0);
		for (int i=1; i<=m; ++i) get_path(x[i], y[i], i);
		build(1, 1, m);
		bitset<blc> ans_p, ans_e;
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			ans_p.reset(); ans_e.reset();
			query(1, l, r, ans_p, ans_e);
			printf("%d\n", int(ans_p.count()-ans_e.count()));
		}
	}
}

namespace task2{
	const int blc=30010;
	int tl[blc<<2], tr[blc<<2], tot;
	bitset<blc> dat_p[blc<<2], dat_e[blc<<2], pre_p[blc], pre_e[blc], pre[blc];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define datp(p) dat_p[p]
	#define date(p) dat_e[p]
	void get_path(int u, int v, int id) {
		if (u>v) swap(u, v);
		pre_p[id]=pre[u-1]^pre[v];
		pre_e[id]=pre[u]^pre[v];
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {datp(p)=pre_p[l]; date(p)=pre_e[l]; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		datp(p)=datp(p<<1)|datp(p<<1|1);
		date(p)=date(p<<1)|date(p<<1|1);
	}
	void query(int p, int l, int r, bitset<blc>& ansp, bitset<blc>& anse) {
		if (l<=tl(p)&&r>=tr(p)) {ansp|=datp(p); anse|=date(p); return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) query(p<<1, l, r, ansp, anse);
		if (r>mid) query(p<<1|1, l, r, ansp, anse);
	}
	void init() {
		for (int i=1; i<=n; ++i) pre[i]=pre[i-1], pre[i][i]=1;
	}
	void solve() {
		init();
		for (int i=1; i<n; ++i) add(g[i].fir, g[i].sec), add(g[i].sec, g[i].fir);
		dep[1]=1; dfs1(1, 0);
		for (int i=1; i<=m; ++i) get_path(x[i], y[i], i);
		build(1, 1, m);
		bitset<blc> ans_p, ans_e;
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			ans_p.reset(); ans_e.reset();
			query(1, l, r, ans_p, ans_e);
			printf("%d\n", int(ans_p.count()-ans_e.count()));
		}
	}
}

namespace task3{
	int ans[N];
	vector<int> que[N];
	int siz[N], msiz[N], mson[N], top[N], rk[N], id[N], back[N], tot, now;
	void dfs1(int u, int fa) {
		siz[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dep[v]=dep[u]+1; back[v]=u;
			dfs1(v, u);
			siz[u]+=siz[v];
			if (siz[v]>msiz[u]) msiz[u]=siz[v], mson[u]=v;
		}
	}
	void dfs2(int u, int f, int t) {
		top[u]=t;
		rk[id[u]=++now]=u;
		if (!mson[u]) return ;
		dfs2(mson[u], u, t);
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==f || v==mson[u]) continue;
			dfs2(v, u, v);
		}
	}

	int tl[N<<2], tr[N<<2], tag[N<<2], sump[N<<2], sume[N<<2], cntp[N<<2], cnte[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define sump(p) sump[p]
	#define sume(p) sume[p]
	#define cntp(p) cntp[p]
	#define cnte(p) cnte[p]
	#define tag(p) tag[p]
	inline void pushup(int p) {
		sump(p)=sump(p<<1)+sump(p<<1|1);
		sume(p)=sume(p<<1)+sume(p<<1|1);
		cntp(p)=cntp(p<<1)+cntp(p<<1|1);
		cnte(p)=cnte(p<<1)+cnte(p<<1|1);
	}
	inline void spread(int p) {
		if (!tag(p)) return ;
		sump(p<<1)=cntp(p<<1); sume(p<<1)=cnte(p<<1); tag(p<<1)=tag(p);
		sump(p<<1|1)=cntp(p<<1|1); sume(p<<1|1)=cnte(p<<1|1); tag(p<<1|1)=tag(p);
		tag(p)=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {
			if (rk[l]<=n) cntp[p]=1;
			else cnte[p]=1;
			return ;
		}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void upd(int p, int l, int r) {
		if (l<=tl(p)&&r>=tr(p)) {sump(p)=cntp(p); sume(p)=cnte(p); tag(p)=1; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r);
		if (r>mid) upd(p<<1|1, l, r);
		pushup(p);
	}

	void upd(int u, int v) {
		while (top[u]!=top[v]) {
			if (dep[top[u]]<dep[top[v]]) swap(u, v);
			upd(1, id[top[u]], id[u]);
			u=back[top[u]];
		}
		if (dep[u]>dep[v]) swap(u, v);
		upd(1, id[u], id[v]);
	}

	void solve() {
		int tot=n;
		for (int i=1; i<n; ++i) {
			++tot;
			add(g[i].fir, tot); add(tot, g[i].fir);
			add(tot, g[i].sec); add(g[i].sec, tot);
		}
		dep[1]=1; dfs1(1, 0); dfs2(1, 0, 1);
		build(1, 1, now);
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			que[r].pb(i);
		}
		for (int i=1; i<=m; ++i) {
			upd(x[i], y[i]);
			ll t=sump(1)-sume(1);
			for (auto it:que[i]) ans[it]=t;
		}
		for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
	}
}

namespace task{
	vector<pair<int, int>> que[N], add[N], del[N];
	int left[N], right[N], ans[N], bit[N];
	int siz[N], msiz[N], mson[N], top[N], rk[N], id[N], back[N], tot;
	int tl[N<<2], tr[N<<2], tag[N<<2], val[N<<2];
	inline void upd(int i, int dat) {for (; i<=m; i+=i&-i) bit[i]+=dat;}
	inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
	inline void upd(int l, int r, int dat) {upd(l, dat); upd(r+1, -dat);}
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define tag(p) tag[p]
	#define val(p) val[p]
	inline void spread(int p) {
		if (!tag(p)) return ;
		val(p<<1)=tag(p); tag(p<<1)=tag(p);
		val(p<<1|1)=tag(p); tag(p<<1|1)=tag(p);
		tag(p)=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; val(p)=tag(p)=0;
		if (l==r) 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 dat) {
		if (l<=tl(p)&&r>=tr(p)) {val(p)=tag(p)=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, dat);
		if (r>mid) upd(p<<1|1, l, r, dat);
	}
	int query(int p, int pos) {
		if (tl(p)==tr(p)) return val(p);
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) return query(p<<1, pos);
		else return query(p<<1|1, pos);
	}
	void dfs1(int u, int fa) {
		siz[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dep[v]=dep[u]+1; back[v]=u;
			dfs1(v, u);
			siz[u]+=siz[v];
			if (siz[v]>msiz[u]) msiz[u]=siz[v], mson[u]=v;
		}
	}
	void dfs2(int u, int f, int t) {
		top[u]=t;
		rk[id[u]=++tot]=u;
		if (!mson[u]) return ;
		dfs2(mson[u], u, t);
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==f || v==mson[u]) continue;
			dfs2(v, u, v);
		}
	}
	void cover_l(int u, int v, int col) {
		while (top[u]!=top[v]) {
			if (dep[top[u]]<dep[top[v]]) swap(u, v);
			upd(1, id[top[u]], id[u], col);
			u=back[top[u]];
		}
		if (dep[u]>dep[v]) swap(u, v);
		if (id[u]<id[v]) upd(1, id[u]+1, id[v], col);
	}
	void cover_r(int u, int v, int col) {
		while (top[u]!=top[v]) {
			if (dep[top[u]]<dep[top[v]]) swap(u, v);
			upd(1, id[top[u]], id[u], col);
			u=back[top[u]];
		}
		if (dep[u]>dep[v]) swap(u, v);
		upd(1, id[u], id[v], col);
	}
	int lca(int u, int v) {
		while (top[u]!=top[v]) {
			if (dep[top[u]]<dep[top[v]]) swap(u, v);
			u=back[top[u]];
		}
		if (dep[u]>dep[v]) swap(u, v);
		return u;
	}
	void solve() {
		for (int i=1; i<n; ++i) ::add(g[i].fir, g[i].sec), ::add(g[i].sec, g[i].fir);
		dep[1]=1; dfs1(1, 0); dfs2(1, 0, 1);
		build(1, 1, n);
		for (int i=1; i<=m; ++i) {
			left[i]=query(1, id[lca(x[i], y[i])]);
			cover_l(x[i], y[i], i);
			add[i].pb({left[i]+1, i});
		}
		build(1, 1, n);
		for (int i=m; i; --i) {
			right[i]=query(1, id[lca(x[i], y[i])]);
			cover_r(x[i], y[i], i);
			del[right[i]].pb({left[i]+1, i});
		}
		// cout<<"left : "; for (int i=1; i<=m; ++i) cout<<left[i]<<' '; cout<<endl;
		// cout<<"right: "; for (int i=1; i<=m; ++i) cout<<right[i]<<' '; cout<<endl;
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			que[r].pb({l, i});
		}
		for (int i=1; i<=m; ++i) {
			// cout<<"i: "<<i<<endl;
			for (auto it:add[i]) upd(it.fir, it.sec, 1); //, cout<<"add: "<<it.fir<<' '<<it.sec<<endl;
			for (auto it:del[i]) upd(it.fir, it.sec, -1); //, cout<<"del: "<<it.fir<<' '<<it.sec<<endl;
			for (auto it:que[i]) ans[it.sec]=query(it.fir);
		}
		for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
	}
}

signed main()
{
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);

	n=read(); m=read(); q=read();
	memset(head, -1, sizeof(head));
	for (int i=1; i<n; ++i) g[i].fir=read(), g[i].sec=read();
	for (int i=1; i<=m; ++i) x[i]=read(), y[i]=read();
	// if (n<=100) force::solve();
	// else if (n<=1000) task1::solve();
	// else if (n<=30000) task2::solve();
	// else task3::solve();
	task::solve();

	return 0;
}
posted @ 2022-03-18 17:34  Administrator-09  阅读(2)  评论(0编辑  收藏  举报