Live2D

CF1556G Gates to Another World

link

Solution

首先不难想到倒过来,变成每次加入一个区间。

考虑如何判断,我们可以考虑用线段树进行优化,即对于一个子树左子树的叶子往右叶子的对应叶子节点连边,然后用并查集。

但是你发现有 \(2^{50}\) 个点,这样肯定是不行的。但是你发现这个题中有用的节点不多,对于未被操作过的线段树上的节点可以发现它子树内的叶子的连通性永远是保持一致的,所以其实我们可以把这个玩意视作一个点。

然后我们就可以做到 \(\Theta(n^2m)\) 了。因为对于一个节点,最多只有 \(\Theta(n)\) 个祖先,也就只有那么多个对应叶子。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define ll long long
#define MAXM 5000005
#define MAXN 50005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m;

int rt,tot,ls[MAXM],rs[MAXM],cov[MAXM];

void pushdown (int x){
	if (!cov[x]) return ;
	if (!ls[x]) ls[x] = ++ tot;
	if (!rs[x]) rs[x] = ++ tot;
	cov[ls[x]] = cov[rs[x]] = cov[x],cov[x] = 0;
}

void modify (int &x,ll l,ll r,ll ql,ll qr,int v){
	if (!x) x = ++ tot;
	if (l > qr || ql > r) return ;
	if (l >= ql && r <= qr) return cov[x] = v,void ();
	ll mid = l + r >> 1;pushdown (x);
	modify (ls[x],l,mid,ql,qr,v);
	modify (rs[x],mid + 1,r,ql,qr,v);
}

int fa[MAXM];
int findSet (int x){return fa[x] == x ? x : fa[x] = findSet (fa[x]);}
void unionSet (int u,int v){fa[findSet (u)] = findSet (v);}

#define pii pair<int,int>
#define se second
#define fi first
vector <pii> g[MAXN];

bool leaf (int x){return !ls[x] && !rs[x];}
void linkit (int u,int v){//要两棵子树对应节点连边
	if (leaf(u) && leaf(v)) g[min (cov[u],cov[v])].push_back ({u,v});
	else if (leaf(u)) linkit (u,ls[v]),linkit (u,rs[v]);
	else if (leaf(v)) linkit (ls[u],v),linkit (rs[u],v);
	else linkit (ls[u],ls[v]),linkit (rs[u],rs[v]);
}

int findpos (int x,ll l,ll r,ll pos){
	if (leaf(x)) return x;
	ll mid = l + r >> 1;
	if (pos <= mid) return findpos (ls[x],l,mid,pos);
	else return findpos (rs[x],mid + 1,r,pos);
}

struct node{
	int typ;ll u,v;
}seq[MAXN];
bool ans[MAXN];

signed main(){
	read (n,m);ll up = (1ll << n) - 1;
	cov[rt = tot = 1] = m + 1;
	for (Int i = 1;i <= m;++ i){
		char str[10] = {};scanf ("%s",str + 1);
		ll u,v;read (u,v);
		if (str[1] == 'b') seq[i].typ = 1,modify (rt,0,up,u,v,i);
		else seq[i] = node{0,u,v};
	}
	for (Int i = 1;i <= tot;++ i) fa[i] = i;
	for (Int i = 1;i <= tot;++ i) if (!leaf(i)) linkit (ls[i],rs[i]);
	for (pii it : g[m + 1]) unionSet (it.fi,it.se);
	for (Int i = m;i >= 1;-- i){
		for (pii it : g[i]) unionSet (it.fi,it.se);
		if (!seq[i].typ)
			ans[i] = (findSet (findpos (rt,0,up,seq[i].u)) == findSet (findpos (rt,0,up,seq[i].v)));
	}
	for (Int i = 1;i <= m;++ i) if (!seq[i].typ) write (ans[i]),putchar ('\n');
    return 0;
}
posted @ 2022-10-13 20:36  Dark_Romance  阅读(29)  评论(0编辑  收藏  举报