CCPC-Wannafly Winter Camp(秦皇岛)Day3:数据结构学习记录

Problem 1

题目链接:BZOJ4423: [AMPPZ2013] Bytehattan

Description
给一张n × m的网格图,每次删去一条边,询问删完之后这条边的
两个端点是否联通。

Solution

对偶图 + 并查集。

对偶图: 是将这个平面的每个区域看成点,原图每一条边所属的两个相邻的区域对应在对偶图中的点有连边。比如下面这张图:
CCPC-Wannafly Winter Camp(秦皇岛)Day3:数据结构学习记录_第1张图片
蓝色的部分就是一个平面图,红色的就是它的对偶图。

回到这道题:
由于强制在线,不能时光倒流+加边。那么可以考虑对偶图。
对于每条线段挨着的两个面积块,如果它们之间是连通的,那么删除这条线段后这两个面积块会在一个环中,且这个环包含且只包含两个端点中的一个(即一个点在环里,一个点在环外),则原图即为不能连通。反过来也成立。
所以只需要把平面图删边转化为对偶图加边就可以了。然后用并查集维护一下连通性即可。

也就是说,在平面图上删边相当于在对偶图上加边,在平面图上是否联通转化为在对偶图上是否不连通,类似于平面图的最大流转化为对偶图的最短路。

Code

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define fi first
#define se second
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e9 + 7;
const int MaxN = 1505;

int fa[MaxN * MaxN];
int n, k;
int pos[MaxN][MaxN];

void init() {
	int cnt = 0;
	for(int i = 1; i < n; i++)
		for(int j = 1; j < n; j++)
			pos[i][j] = ++cnt;
    for(int i = 1; i <= n * n; i++) fa[i] = i;
}

int find(int x) { 
	return fa[x]==x ? x : fa[x]=find(fa[x]); 
}

int main()
{
    scanf("%d %d", &n, &k);
    init();
    int flag = 0;
	while(k--) {
		int a, b, c, d; char p[5], q[5];
		scanf("%d %d %s %d %d %s", &a, &b, p, &c, &d, q);
		int x, y;
		if(flag) a = c, b = d, p[0] = q[0];
		if(p[0] == 'N') x = pos[a][b], y = pos[a-1][b];
		else x = pos[a][b], y = pos[a][b-1];

		if(find(x) == find(y)) flag = 1, printf("NIE\n");
		else flag = 0, printf("TAK\n");
		fa[find(x)] = fa[find(y)];
	}
    return 0;
}

Problem 2

Description
有n个东西,每个东西有两个属性ai和bi,每个东西你只能选择1个属性。你需要选择A个a属性以及B个b属性,使得属性和最大。

按照a排序,枚举最后一个a的位置,之后都选b,之前都被选了,
其中被选了a的是那些b − a较小的。

Problem 3

题目链接:Codeforces Round #250 (Div. 1) D. The Child and Sequence

Description
区间对p取模,询问区间和。

Solution

对于区间和这个问题,利用线段树就可以轻松解决,但是问题是如何对一段区间内的每个数取模?这个线段树是做不到的,那么来考虑取模的意义和影响。

对于每个数 x,对 y 取模后,x mod y 的值必然比 y 小。如果 y < x/2,那么 x 就会变得小于 x/2,如果 y 大于 x/2,即 x 剩下的部分比 x/2 少,那么取模后 x 也会变得比 x/2 小。所以不难得出,对于一个数 x,有效的取 mod 最多进行 logx 次,也就是说一共最多只会进行nlogn次取模,所以即使暴力对所有的数取模,时间复杂度也是可以接受的。

对于一段区间,如果取模的数比这段区间所有的数都大,那取模就是没有意义的。也就是说,如果取模的数比区间的最大值还大,那么就不需要取模了。

所以我们在线段树里再记录一个区间最大值,如果取模的数大于最大值,就不进行此次操作,如果小于最大值,就暴力取模。

Problem 4

Description
插入一条线段,询问某个x坐标上最高的线段(只涉及整数)

Solution

你可能感兴趣的:(线段树)