题解 牛半仙的妹子Tree
听说RMQ+暴力能直接水过去
正解是个神奇的「对询问分块」
如果没有操作2,直接一遍BFS下去可以 \(O(n)\) 出解
如果只有很少的几次操作1/操作3,可以对每个操作3暴力枚举操作1,看在不在影响范围之内
这两种写法单独用都会T,考虑综合用
以操作2为依据进行分块:
当两个操作2间的间隔 \(\geqslant \sqrt m\) 时,用方案1的BFS,最多有 \(\sqrt m\) 个块,单个块 \(O(n)\)
当两个操作2间的间隔 \(< \sqrt m\) 时,用方案2枚举匹配,最多 \(\sqrt m\) 个块,单个块 \(O(\sqrt m*\sqrt m)=O(m)\)
所以总复杂度是 \(O(n\sqrt m)\)
- 当题目中有「清空」操作时,可以试着搭配「按题意模拟」和「对每次查询,暴力枚举修改」,对询问分块以优化复杂度
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#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;
int head[N], size, this2[N], nxt2[N], dep[N], mdep[N<<2], tot, id[N], st[29][N<<2], len, top;
queue<int> q1, q2;
pair<int, int> sta[N];
bool vis[N];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
struct que{int op, x;}q[N];
void dfs(int u, int fa) {
mdep[++tot]=dep[u]; id[u]=tot;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dep[v]=dep[u]+1; dfs(v, u);
mdep[++tot]=dep[u];
}
}
int lca(int a, int b) {
if (id[a]>id[b]) swap(a, b);
int t=log2(id[b]-id[a]+1);
//cout<<"log: "<<int(id[b]-id[a]+1)<<endl;
//printf("log: %.100lf\n", log(id[b]-id[a]+1)/log(2));
//printf("log2: %.100lf\n", log2(id[b]-id[a]+1));
return min(st[t][id[a]], st[t][id[b]-(1<<t)+1]);
}
inline int dis(int a, int b) {return dep[a]+dep[b]-2*lca(a, b);}
signed main()
{
memset(head, -1, sizeof(head));
n=read(); m=read(); len=sqrt(m);
for (int i=1,u,v; i<n; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
}
for (int i=1; i<=m; ++i) q[i].op=read(), q[i].x=read();
q[m+1].op=2;
for (int i=m+1,lst=m+1; i; --i) {
nxt2[i]=lst;
if (q[i].op==2) lst=i;
}
dep[1]=1; dfs(1, 0);
//cout<<"mdep: "; for (int i=1; i<=tot; ++i) cout<<mdep[i]<<' '; cout<<endl;
for (int i=1; i<=tot; ++i) st[0][i]=mdep[i];
int t=log2(tot);
for (int j=1; j<=t; ++j)
for (int i=1; i<=tot-(1<<j)+1; ++i)
st[j][i] = min(st[j-1][i], st[j-1][i+(1<<(j-1))]);
for (int i=1; i<=m; ++i) {
//cout<<"i: "<<i<<' '<<q[i].op<<' '<<q[i].x<<endl;
if (i==1 || q[i].op==2) {
if (nxt2[i]-i<=len) {
top=0;
for (int j=i+(q[i].op==2); j<nxt2[i]; ++j) {
if (q[j].op==1) sta[++top]=make(j, q[j].x);
else {
//cout<<"try: "<<j<<endl;
for (int k=1; k<=top; ++k) {
//cout<<"dis: "<<sta[k].sec<<' '<<q[j].x<<' '<<dis(sta[k].sec, q[j].x)<<endl;
if (dis(sta[k].sec, q[j].x) <= j-sta[k].fir) {
puts("wrxcsd");
goto jump;
}
}
puts("orzFsYo");
jump: ;
}
}
i=nxt2[i]-1;
continue;
}
else {memset(vis, 0, sizeof(vis)); while (q1.size()) q1.pop();}
if (q[i].op==2) continue;
}
assert(!q2.size());
int u;
while (q1.size()) {
u=q1.front(); q1.pop();
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (!vis[v]) vis[v]=1, q2.push(v);
}
}
swap(q1, q2);
if (q[i].op==1) {if (!vis[q[i].x]) vis[q[i].x]=1, q1.push(q[i].x);}
else puts(vis[q[i].x]?"wrxcsd":"orzFsYo");
}
return 0;
}