题解 牛半仙的妹子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;
}
posted @ 2021-09-07 16:35  Administrator-09  阅读(17)  评论(0编辑  收藏  举报