[CF1416D]Graph and Queries

137 篇文章 1 订阅
122 篇文章 0 订阅

题目

传送门 to luogu

思路

引用某大佬的一句话:因为 LCT 是垃圾,所以我们不考虑它。不好意思搞错了,是这一句:

对于删边,我们的处理工具很有限。要么是对询问分块,要么是删边转化为加边。

所以这道题我们只好将删边转换为加边。这样想的原因还是 维护连通块。两个连通块通过加边来合成。这玩意儿不像线段树么?

然后,比较套路的,想到类似于克鲁斯卡尔重构树的东西。想到对子树进行操作。想到线段树维护 d f n dfn dfn c o m m o n    t r i c k \rm common\; trick commontrick 。然后意识到 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 做完了。

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MaxN = 200005;
int n, p[MaxN];

int son[MaxN<<1][2];
namespace UFS{
	int fa[MaxN<<1], totNode;
	inline int findFa(int a){
		if(a != fa[a])
			fa[a] = findFa(fa[a]);
		return fa[a];
	}
	void init(){
		for(int i=0; i<(MaxN<<1); ++i)
			fa[i] = i; // single
		totNode = 0; // clear
	}
	inline void merg(int a,int b){
		a = findFa(a), b = findFa(b);
		if(a == b) return ;
		int x = ++ totNode;
		son[x][0] = a, fa[a] = x;
		son[x][1] = b, fa[b] = x;
	}
}

int st[MaxN<<1], ed[MaxN<<1];
int dfn, num[MaxN];
void dfs(int x){
	st[x] = dfn+1; // hesitate
	if(!son[x][0]) // a leaf
		num[++ dfn] = p[x];
	else{
		dfs(son[x][0]);
		dfs(son[x][1]);
	}
	ed[x] = dfn;
}

namespace SgTree{
	inline int id(int l,int r){
		return (l+r)|(l!=r);
	}
	int v[MaxN<<1];
	void pushUp(int l,int r){
		int m = (l+r)>>1, o = id(l,r);
		v[o] = v[id(m+1,r)];
		if(num[v[o]] < num[v[id(l,m)]])
			v[o] = v[id(l,m)];
	}
	void build(int l=1,int r=n){
		if(l == r){
			v[id(l,r)] = l;
			return ;
		}
		build(l,(l+r)>>1);
		build((l+r)/2+1,r);
		pushUp(l,r);
	}
	int query(int ql,int qr,int l=1,int r=n){
		if(ql <= l && r <= qr)
			return v[id(l,r)];
		int m = (l+r)>>1;
		if(qr <= m) return query(ql,qr,l,m);
		if(m < ql) return query(ql,qr,m+1,r);
		int las = query(ql,qr,m+1,r);
		int ras = query(ql,qr,l,m);
		if(num[las] > num[ras])
			return las;
		else return ras; // find max
	}
	void modify(int qid,int l=1,int r=n){
		if(l == r){
			num[qid] = 0; return ;
		}
		if(qid <= ((l+r)>>1))
			modify(qid,l,(l+r)>>1);
		else modify(qid,(l+r)/2+1,r);
		pushUp(l,r); 
	}
}

const int MaxQ = 500005;
struct CMD{
	int opt, x;
};
CMD cmd[MaxQ];

const int MaxM = 300005;
struct Edge{
	int zxy, sxy;
};
Edge e[MaxM];
bool fucked[MaxM];

int main(){
	UFS::init(); // init all
	UFS::totNode = n = readint();
	int m = readint();
	int q = readint();
	for(int i=1; i<=n; ++i)
		p[i] = readint();
	for(int i=1; i<=m; ++i){
		e[i].zxy = readint();
		e[i].sxy = readint();
	}
	for(int i=1; i<=q; ++i){
		cmd[i].opt = readint();
		cmd[i].x = readint();
		if(cmd[i].opt == 2)
			fucked[cmd[i].x] = 1;
	}
	for(int i=1; i<=m; ++i){
		if(fucked[i]) continue;
		UFS::merg(e[i].zxy,e[i].sxy);
	}
	for(int i=q; i>=1; --i){
		if(cmd[i].opt == 2)
			UFS::merg(
				e[cmd[i].x].zxy,
				e[cmd[i].x].sxy
			);
		else cmd[i].x = UFS::
			findFa(cmd[i].x);
	}
	for(int i=1; i<=UFS::totNode; ++i)
		if(UFS::findFa(i) == i)
			dfs(i); // all root
	SgTree::build();
	for(int i=1,x; i<=q; ++i){
		if(cmd[i].opt == 2)
			continue;
		x = SgTree::query(
			st[cmd[i].x],
			ed[cmd[i].x]
		);
		printf("%d\n",num[x]);
		SgTree::modify(x);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值