CF960F CDQ分治

首先,这不是正解,甚至歪的很过分,你还要吸氧,但是我就是要发。
根据题意我们可以知道首先要求

  1. 转移的路径编号的转移必须是从小到大
  2. 转移的权值必须从小到大
  3. 一条边的终点转移到另一条边的起点,起点终点需要相同

我的思路是什么呢,这是三个要求,而且头两个要求很二维偏序对不对,那么第三个要求我们可以稍稍强行理解一下一下然后上CDQ分治,毕竟模板的CDQ分治就是三维偏序。
要考虑怎么写CDQ分治,首先这里的瓶颈是什么就是条件三,那我们在CDQ分治的时候就可以和普通的处理不太一样,我们之前的处理都是处理中点之前的修改,回答中点之后的询问,利用树状数组去解决。但是如果在这题我们直接使用树状数组的话会有一个问题,你当前边的权值为V,你在树状数组里找权值小于V的最大值有可能那条边是非法的,就是不能满足条件3.
我们的处理方案是什么呢,就是遍历一遍区间,把所有的点拿出来,按照修改的终点和查询的起点相同的那些路拿出来单独处理,分多次处理,这样树状数组里的都是合法的值都可以转移。然后由于总边数是固定的,所以这样子的操作不会改变复杂度。
由于树状数组的log,所以总复杂度是两个log,但是又由于我们在路上用了很多stl,所以常数有点大,你还得丢人的去吸氧。

int B[max_], MC = 1e5 + 7;
inline void Ins(int i, int x) { for (; i <= MC; i += i & -i) B[i] = max(B[i], x); }
inline void Clr(int i) { for (; i <= MC; i += i & -i) B[i] = 0; }
inline int Qur(int i) { int A = 0; for (; i; i -= i & -i) A = max(A, B[i]); return A; }
int N, M,qn;
struct kk {
	int op, id, now, to, val,yuanid;//op = 1;修改 ,op = 0是询问
	kk(){}
	kk(int a, int b, int c, int d, int e,int f) {
		op = a, id = b, now = c, to = d, val = e,yuanid = f;
	}
}node[2 * max_];
queue<kk> que[max_];
set<int> S;
int f[max_];
void dfs(int L, int R) {
	if (L == R)return;
	int mid = (L + R) >> 1;
	dfs(L, mid);
	for (int i = L; i <= R; i++) {
		if (node[i].id <= mid && node[i].op == 1) {//修改
			if (!S.count(node[i].to))S.insert(node[i].to);
			que[node[i].to].push(node[i]);
		}
		if (node[i].id > mid && node[i].op == 0) {//询问
			if (!S.count(node[i].now))S.insert(node[i].now);
			que[node[i].now].push(node[i]);
		}
	}
	for (auto quanzhi : S) {
		set<int> del;
		while (!que[quanzhi].empty()){
			kk tou = que[quanzhi].front(); que[quanzhi].pop();
			if (tou.op == 1) {
				if (!del.count(tou.val))del.insert(tou.val);
				Ins(tou.val, f[tou.yuanid]);
			}
			else {
				int t = Qur(tou.val - 1);
				f[tou.yuanid] = max(f[tou.yuanid], t + 1);
			}
		}
		for (auto to : del) {
			Clr(to);
		}
		del.clear();
	}
	S.clear();
	dfs(mid + 1, R);
}
signed main() {
	N = read(); M = read();
	for (int i = 1; i <= M; i++) {
		f[i] = 1;
		int now = read(), to = read(), val = read();
		++qn;node[qn] = kk(0, qn, now, to, val + 1,i);
		++qn; node[qn] = kk(1, qn, now, to, val + 1,i);
	}
	dfs(1, qn);
	int ans = 0;
	for (int i = 1; i <= M; i++) {
		//cout << f[i] << " ";
		ans = max(ans, f[i]);
	}
	cout << ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值