题解 农民

传送门

发现限制在每个点到根的路径上的每条边上
那么树剖即可,子树 dfs 序连续所以可以直接打标记翻转
复杂度 \(O(n\log^2n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#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;
int a[N], ls[N], rs[N], fa[N], rot;

namespace force{
	bool query(int x) {
		int liml=-INF, limr=INF;
		for (int now=x; now!=rot; now=fa[now]) {
			if (now==ls[fa[now]]) limr=min(limr, a[fa[now]]-1);
			else liml=max(liml, a[fa[now]]+1);
		}
		return liml<=a[x]&&a[x]<=limr;
	}
	void dfs(int u) {
		if (!u) return ;
		swap(ls[u], rs[u]);
		dfs(ls[u]); dfs(rs[u]);
	}
	void solve() {
		for (int i=1,op,x,y; i<=m; ++i) {
			op=read(); x=read();
			if (op==1) a[x]=read();
			else if (op==2) dfs(x);
			else puts(query(x)?"YES":"NO");
		}
	}
}

namespace task1{
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	int tl[N<<2], tr[N<<2];
	const int leq=1, geq=0;
	int siz[N], id[N], tot;
	multiset<int> datl[N<<2], datg[N<<2];
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		datl[p].insert(INF), datg[p].insert(-INF);
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void add(int p, int l, int r, int val, int op) {
		if (l<=tl(p)&&r>=tr(p)) {
			if (op==leq) datl[p].insert(val);
			else datg[p].insert(val);
			return ;
		}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) add(p<<1, l, r, val, op);
		if (r>mid) add(p<<1|1, l, r, val, op);
	}
	void del(int p, int l, int r, int val, int op) {
		if (l<=tl(p)&&r>=tr(p)) {
			if (op==leq) datl[p].erase(datl[p].find(val));
			else datg[p].erase(datg[p].find(val));
			return ;
		}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) del(p<<1, l, r, val, op);
		if (r>mid) del(p<<1|1, l, r, val, op);
	}
	bool query(int p, int pos, int rk, int liml, int limr) {
		liml=max(liml, *datg[p].rbegin()), limr=min(limr, *datl[p].begin());
		if (tl(p)==tr(p)) {
			// int liml=*datg[p].rbegin(), limr=*datl[p].begin();
			return liml<=a[rk]&&a[rk]<=limr;
		}
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) return query(p<<1, pos, rk, liml, limr);
		else return query(p<<1|1, pos, rk, liml, limr);
	}
	void upd(int x, int val) {
		if (ls[x]) del(1, id[ls[x]], id[ls[x]]+siz[ls[x]]-1, a[x]-1, leq);
		if (rs[x]) del(1, id[rs[x]], id[rs[x]]+siz[rs[x]]-1, a[x]+1, geq);
		a[x]=val;
		if (ls[x]) add(1, id[ls[x]], id[ls[x]]+siz[ls[x]]-1, a[x]-1, leq);
		if (rs[x]) add(1, id[rs[x]], id[rs[x]]+siz[rs[x]]-1, a[x]+1, geq);
	}
	void dfs1(int u) {
		siz[u]=1; id[u]=++tot;
		if (ls[u]) dfs1(ls[u]), siz[u]+=siz[ls[u]];
		if (rs[u]) dfs1(rs[u]), siz[u]+=siz[rs[u]];
	}
	void solve() {
		dfs1(rot);
		build(1, 1, n);
		for (int i=1; i<=n; ++i) {
			if (ls[i]) add(1, id[ls[i]], id[ls[i]]+siz[ls[i]]-1, a[i]-1, leq);
			if (rs[i]) add(1, id[rs[i]], id[rs[i]]+siz[rs[i]]-1, a[i]+1, geq);
		}
		for (int i=1,op,x,y; i<=m; ++i) {
			op=read(); x=read();
			if (op==1) upd(x, read());
			else if (op==2) assert(0);
			else puts(query(1, id[x], x, -INF, INF)?"YES":"NO");
		}
	}
}

namespace task{
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	const int leq=1, geq=0;
	pair<int, int> liml[N<<2], limg[N<<2];
	int tl[N<<2], tr[N<<2], tag[N<<2], rev[N<<2];
	int siz[N], msiz[N], mson[N], top[N], rk[N], id[N], tot;
	void spread(int p) {
		if (!rev[p]) return ;
		swap(liml[p<<1], limg[p<<1]), rev[p<<1]^=1;
		swap(liml[p<<1|1], limg[p<<1|1]), rev[p<<1|1]^=1;
		rev[p]=0;
	}
	inline void pushup(int p) {
		liml[p]={min(liml[p<<1].fir, liml[p<<1|1].fir), max(liml[p<<1].sec, liml[p<<1|1].sec)};
		limg[p]={min(limg[p<<1].fir, limg[p<<1|1].fir), max(limg[p<<1].sec, limg[p<<1|1].sec)};
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		liml[p]={INF, INF}, limg[p]={-INF, -INF};
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void add(int p, int pos, int val, int op) {
		if (tl(p)==tr(p)) {
			if (op==leq) liml[p]={val, val};
			else limg[p]={val, val};
			return ;
		}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) add(p<<1, pos, val, op);
		else add(p<<1|1, pos, val, op);
		pushup(p);
	}
	void del(int p, int pos, int val, int op) {
		if (tl(p)==tr(p)) {
			if (op==leq) liml[p]={INF, INF};
			else limg[p]={-INF, -INF};
			return ;
		}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) del(p<<1, pos, val, op);
		else del(p<<1|1, pos, val, op);
		pushup(p);
	}
	void reverse(int p, int l, int r) {
		if (l<=tl(p)&&r>=tr(p)) {swap(liml[p], limg[p]); rev[p]^=1; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) reverse(p<<1, l, r);
		if (r>mid) reverse(p<<1|1, l, r);
		pushup(p);
	}
	pair<int, int> query(int p, int l, int r) {
		if (l<=tl(p)&&r>=tr(p)) return {limg[p].sec, liml[p].fir};
		spread(p);
		int mid=(tl(p)+tr(p))>>1; pair<int, int> ans={-INF, INF}, t;
		if (l<=mid) t=query(p<<1, l, r), ans.fir=max(ans.fir, t.fir), ans.sec=min(ans.sec, t.sec);
		if (r>mid) t=query(p<<1|1, l, r), ans.fir=max(ans.fir, t.fir), ans.sec=min(ans.sec, t.sec);
		return ans;
	}
	void dfs1(int u) {
		siz[u]=1;
		if (ls[u]) dfs1(ls[u]), siz[u]+=siz[ls[u]];
		if (rs[u]) dfs1(rs[u]), siz[u]+=siz[rs[u]];
		mson[u]=siz[ls[u]]>siz[rs[u]]?ls[u]:rs[u];
	}
	void dfs2(int u, int t) {
		top[u]=t;
		rk[id[u]=++tot]=u;
		if (!mson[u]) return ;
		dfs2(mson[u], t);
		if (ls[u]&&ls[u]!=mson[u]) dfs2(ls[u], ls[u]);
		if (rs[u]&&rs[u]!=mson[u]) dfs2(rs[u], rs[u]);
	}
	void upd(int x, int val) {
		if (ls[x]) del(1, id[ls[x]], a[x]-1, leq);
		if (rs[x]) del(1, id[rs[x]], a[x]+1, geq);
		a[x]=val;
		if (ls[x]) add(1, id[ls[x]], a[x]-1, leq);
		if (rs[x]) add(1, id[rs[x]], a[x]+1, geq);
	}
	bool query(int x) {
		int pos=x;
		pair<int, int> lim={-INF, INF};
		while (top[x]!=top[rot]) {
			pair<int, int> t=query(1, id[top[x]], id[x]);
			// cout<<"t: ("<<t.fir<<','<<t.sec<<")"<<endl;
			lim.fir=max(lim.fir, t.fir);
			lim.sec=min(lim.sec, t.sec);
			x=fa[top[x]];
		}
		pair<int, int> t=query(1, id[rot], id[x]);
		// cout<<"t: ("<<t.fir<<','<<t.sec<<")"<<endl;
		lim.fir=max(lim.fir, t.fir);
		lim.sec=min(lim.sec, t.sec);
		// cout<<a[x]<<endl;
		return lim.fir<=a[pos]&&a[pos]<=lim.sec;
	}
	void solve() {
		dfs1(rot); dfs2(rot, rot); build(1, 1, n);
		for (int i=1; i<=n; ++i) {
			if (ls[i]) add(1, id[ls[i]], a[i]-1, leq);
			if (rs[i]) add(1, id[rs[i]], a[i]+1, geq);
		}
		for (int i=1,op,x,y; i<=m; ++i) {
			op=read(); x=read();
			if (op==1) upd(x, read());
			else if (op==2) reverse(1, id[x]+1, id[x]+siz[x]-1);
			else puts(query(x)?"YES":"NO");
		}
	}
}

signed main()
{
	n=read(); m=read();
	for (int i=1; i<=n; ++i) {
		a[i]=read();
		fa[ls[i]=read()]=i;
		fa[rs[i]=read()]=i;
	}
	for (int i=1; i<=n; ++i) if (!fa[i]) {rot=i; break;}
	// cout<<"rot: "<<rot<<endl;
	// if (n<=5000&&m<=5000) force::solve();
	// else task1::solve();
	// assert(n>5000);
	task::solve();

	return 0;
}
posted @ 2022-06-06 06:51  Administrator-09  阅读(0)  评论(0编辑  收藏  举报