Problem 1
题目链接:BZOJ4423: [AMPPZ2013] Bytehattan
Description
给一张n × m的网格图,每次删去一条边,询问删完之后这条边的
两个端点是否联通。
Solution
对偶图 + 并查集。
对偶图: 是将这个平面的每个区域看成点,原图每一条边所属的两个相邻的区域对应在对偶图中的点有连边。比如下面这张图:
蓝色的部分就是一个平面图,红色的就是它的对偶图。
回到这道题:
由于强制在线,不能时光倒流+加边。那么可以考虑对偶图。
对于每条线段挨着的两个面积块,如果它们之间是连通的,那么删除这条线段后这两个面积块会在一个环中,且这个环包含且只包含两个端点中的一个(即一个点在环里,一个点在环外),则原图即为不能连通。反过来也成立。
所以只需要把平面图删边转化为对偶图加边就可以了。然后用并查集维护一下连通性即可。
也就是说,在平面图上删边相当于在对偶图上加边,在平面图上是否联通转化为在对偶图上是否不连通,类似于平面图的最大流转化为对偶图的最短路。
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#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坐标上最高的线段(只涉及整数)