首页 > 其他分享 >题解:CF1007D Ants

题解:CF1007D Ants

时间:2024-10-10 10:11:30浏览次数:7  
标签:la int 题解 CF1007D back tot dfn Ants push

题目传送门

每只蚂蚁只走一对点肯定是不劣的,由此想到 2-sat。

限制条件是:若 \((a,b)\) 和 \((c,d)\) 两条链相交,则不能同时选。直接建图肯定是爆炸的。

用树剖可以将 \((a,b)\) 这条链划分成 \(O(\log n)\) 个区间。因为同一条链的区间不交,限制条件变为若两个区间相交,则这两个点不能同时选。

把这些区间放到线段树上,限制条件变成:选了一个点,这个点在线段树上的祖先(包括自己)上的其他点都不能选。

先连左右儿子,再类似 这题 的前缀优化建图,可以满足线段树上一个区间上的点最多选一个。

具体来说记 \(f_{x, 1 \dots k}\) 表示 \(x\) 点上的前缀或,\(x\) 的左右儿子为 \(ls,rs\),\(x\) 上挂了 \(a_1,a_2 \dots a_k\)。

  1. 将 \(f_{ls,k},f_{rs,k}\) 向 \(f_{x,0}\) 连边。
  2. 连边 \(f_{x,i-1}\) 和 \(f_{x,i}\),\(f_{x,i-1}\) 和 \(\lnot a_i\),\(a_i\) 和 \(f_{x,i}\),当然还要对称连边

最后跑 2-sat 就行了。

时间和空间复杂度都是 \(O(m \log^2 n)\)。

Code:

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cassert>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e6 + 10;
int tot, n, m, top[N], son[N], sz[N], fa[N], dfn[N], dep[N];
int dfn1[N], low[N], c[N], st[N];
vector <int> e[N], pos[N];
void dfs1(int x, int pfa){
	fa[x] = pfa, dep[x] = dep[pfa] + 1, sz[x] = 1;
	for(int y : e[x]){
		if(y == pfa)
			continue;
		dfs1(y, x);
		sz[x] += sz[y];
		if(sz[son[x]] < sz[y])
			son[x] = y;
	}
}
void dfs2(int x, int pfa){
	dfn[x] = ++dfn[0], top[x] = pfa;
	if(son[x])
		dfs2(son[x], pfa);
	for(int y : e[x])
		if(y != fa[x] && y != son[x])
			dfs2(y, y);
}
void update(int id, int l, int r, int x, int y, int a){
	if(x <= l && y >= r){
		pos[id].push_back(a);
		return;
	}
	int mid = (l + r) >> 1;
	if(x <= mid)
		update(2 * id, l, mid, x, y, a);
	if(y > mid)
		update(2 * id + 1, mid + 1, r, x, y, a);
}
void tarjan(int x){
	low[x] = dfn1[x] = ++dfn1[0], st[++st[0]] = x;
	for(int y : e[x]){
		if(!dfn1[y]){
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if(!c[y])
			low[x] = min(low[x], dfn1[y]);
	}
	if(dfn1[x] == low[x]){
		c[x] = ++c[0];
		while(st[st[0]] != x)
			c[st[st[0]--]] = c[0];
		st[0]--;
	}
}
void update(int x, int y, int t){
	while(top[x] != top[y]){
		if(dep[top[x]] < dep[top[y]])
			swap(x, y);
		update(1, 1, n, dfn[top[x]], dfn[x], t);
		x = fa[top[x]];
	}
	if(dfn[x] > dfn[y])
		swap(x, y);
	if(dfn[x] < dfn[y])
		update(1, 1, n, dfn[x] + 1, dfn[y], t);
}
int solve(int id, int l, int r){
	int la = 0;
	if(l != r){
		int mid = (l + r) >> 1, x = solve(2 * id, l, mid), y = solve(2 * id + 1, mid + 1, r);
		if(!x || !y)
			la = x + y;
		else{
			e[x].push_back(tot);
			e[tot ^ 1].push_back(x ^ 1);
			e[y].push_back(tot);
			e[tot ^ 1].push_back(y ^ 1);
			la = tot, tot += 2;
		}
	}
	for(int i : pos[id]){
		if(la){
			e[la].push_back(i ^ 1);
			e[i].push_back(la ^ 1);
			e[la].push_back(tot);
			e[tot ^ 1].push_back(la ^ 1);
			e[i].push_back(tot);
			e[tot ^ 1].push_back(i ^ 1);
			la = tot, tot += 2;
		}
		else
			la = i;
	}
	return la;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	for(int i = 1, u, v; i < n; i++){
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs1(1, 0);
	dfs2(1, 1);
	for(int i = 1; i <= n; i++)
		e[i].clear();
	cin >> m;
	for(int i = 1, a, b, c, d; i <= m; i++){
		cin >> a >> b >> c >> d;
		update(a, b, 2 * i);
		update(c, d, 2 * i + 1);
	}
	tot = 2 * m + 2;
	solve(1, 1, n);
	for(int i = 1; i < tot; i++)
		if(!dfn1[i])
			tarjan(i);
	for(int i = 1; i <= m; i++){
		if(c[2 * i] == c[2 * i + 1]){
			cout << "NO\n";
			return 0;
		}
	}
	cout << "YES\n";
	for(int i = 1; i <= m; i++)
		cout << 1 + (c[2 * i] > c[2 * i + 1]) << "\n";
}

标签:la,int,题解,CF1007D,back,tot,dfn,Ants,push
From: https://www.cnblogs.com/louisliang/p/18455768

相关文章

  • BUUCTF_MISC题解析(6,8)
    6.乌镇峰会种图把打开的图片放进010editor,拉到最末尾就可以发现flag 8.N种方法解决打开文件是KEY.exe点击打不开,运行不了(exe文件是二进制文件),所以把他拉到010editor打开,data:image/jpg;base64,iVBORw0KGgo......gg==发现是base编码的形式,开头的提示说明是jpg格式的图片,......
  • P6309 题解
    很经典但是很好的题目。/qiang标签:线段树。数轴上有一些关键点,不同的关键点可能在同一坐标。关键点的坐标均为整数。支持两种操作:删去/添加一些关键点。取一个点。使得它与\([l,r]\)范围内所有关键点的距离最小。求最小距离。\(\text{关键点的坐标数}\le3\times......
  • 深度学习No module named ‘torchvision.transforms.functional_tensor‘问题解决
    问题在进行深度学习训练过程中出现ModuleNotFoundError:Nomodulenamed'torchvision.transforms.functional_tensor'报错,多方查阅资料后得到了解决方案。关于我的环境:CUDA==12.1torch==2.4.1GPU==4090D原先进行深度学习用的CUDA11.3,torch1.2.1,但是在训练时出现nvrtc......
  • AGC005 题解
    目录A-STringB-MinimumSumC-TreeRestoringA-STring用栈模拟一下即可,具体的,当栈顶出现形如ST时,将其弹出。#include<bits/stdc++.h>#definelllonglongusingnamespacestd;llRead(){ intsig=1; llnum=0; charc=getchar(); while(!isdigit(c))......
  • 2024年江西省职业院校技能大赛高职组“数据库运行与管理“竞赛样题解析答案
    2024年江西省职业院校技能大赛高职组"数据库运行与管理"竞赛样题解析答案文章目录2024年江西省职业院校技能大赛高职组"数据库运行与管理"竞赛样题解析答案模块A:数据库理论模块B:数据库设计与运维`任务一参考答案:``任务二参考答案:`模块C:数据库查询与分析`模块C参考答案:`......
  • [NOIP2006 提高组] 作业调度方案 题解
    题目描述我们现在要利用 m 台机器加工 n 个工件,每个工件都有 m 道工序,每道工序都在不同的指定的机器上完成。每个工件的每道工序都有指定的加工时间。每个工件的每个工序称为一个操作,我们用记号 j-k 表示一个操作,其中 j 为 1 到 n 中的某个数字,为工件号;k 为 ......
  • NewStar CTF 2024 week1 题解
    1.base题目给了以下内容:Thisisabasequestion!4C4A575851324332474E324547554B494A5A4446513653434E564D444154545A4B354D45454D434E4959345536544B474D5134513D3D3D3D观察给出的字符串发现,字符串由数字0-9以及字母A-F组成,于是推测这可能是一个base16编码,于是将其解码,......
  • 2023牛客OI赛前集训营-提高组(第三场) - 题解汇总
    空位与数(game)贪心即可,因为正正得正,负负也得正,所以将两个数组分别按照正负性分开,然后让正数里面大的配上大的,负数里面绝对值大的配上绝对值大的,这样可以让正积总和尽量大。剩下不足的(必须要一正一负相乘的)让绝对值大的配绝对值小的,这样可以让负积总和尽量小。#include<cstdio>#i......
  • webapi发布---问题解决
    一.127.0.0.1是回路地址,来检验本机TCP/IP协议栈,实际使用过程中服务端不在本机,是外部地址,要用IP地址测试。外部用户采用IP+端口号访问,如下图浏览器访问不了,400错误。解决方案:因为IIS7采用了更安全的web.config管理机制,默认情况下会锁住配置项不允许更改。以管理员身份运......
  • 题解:SP6517 JOCHEF - Farmer Sepp
    一眼简单悬线法,而且有多倍经验,感觉这题被遗忘了,那我就拿下这个水紫吧!我们用a数组表示能向上延伸能到达的最大距离,依次遍历每一行,如果该位置为F,他可以从上一行转移过来,将a数组增加一,如果该位置为C,意味着这个位置不能成矩形,将a数组变为0。接下来进行悬线法的标准操作,设l......