题解 数颜色
发现连通块个数 = 被点亮点数 - 被点亮边数
赛时从这里开始思路就僵化了
只会各种试图优化点集,边集求交
其实存在另一个转化:如果将一条路径的边下放到点上,则只有 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;
}