Codeforces Round #310 (Div. 2)补题记录
前三题:556A 556B 556C
A题就是数一下\(0\)和\(1\)的个数求个最小值,B模拟一下就可以了,C题按照题目大意直接暴力,注意拆一次和装一次各算\(1s\),题目没有说太清楚。
D.556D
经典弱化版扫描线。
大意:给你\(n\)个线段,\(m\)个桥,在\(m\)中选择\(n-1\)个,连接相邻的线段。问能不能全连上,如果可以就按照连接的顺序输出桥的编号
思路:
首先第一个样例的图可以是这样子:
转换一下思路,桥的长度是\(x\),连接两个线段最小的长度是\(l\),最大是\(r\)的话。那么如果这个桥可以连接这两个线段,条件就是:\(l\leq x \leq r\)
于是,就变成了判断一个点是否在一个线段内。经典扫描线\(O(n)\)做法。
上面那个图就成了这样:
\([1,4]\)和\([7,8]\)对应着\([3,7]\),etc.
然后对于桥,优先匹配的是左端点最远的线段。这个地方画一下图就会发现,反例都是画不出来的
简述一下扫描线的思路:
首先将线段起点,终点,以及桥的点排序,然后从小到大遍历。遇到起点,就将其记入集合;遇到终点,就寻找匹配的线段,然后在集合内删除该线段。遇到桥,就寻找匹配的线段,然后记录线段和桥的编号,然后在集合内删除该线段的起点。
详细看代码:
#if __cplusplus >= 201103L
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#else
#include <algorithm>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <string.h>
#include <vector>
#endif
using namespace std;
#define inf __INT_MAX__
#define enf INT_MIN
#define INF LLONG_MAX
#define ENF LLONG_MIN
const int MAXN = 2e5 + 10;
const double pi = acos(-1.0);
const double eps = 1e-6;
typedef long long ll;
typedef unsigned long long ull;
#define zhengfu(x) ((x > eps) - (x < -eps))
struct vec {
ll l, r;
int pos;
bool operator<(const vec it)const {
//按照左端点,右端点,类型依次排列
return l == it.l ? (r == it.r ? pos < it.pos : r < it.r) : l < it.l;
}
};
int ans[MAXN];
int main() {
int n, m;
cin >> n >> m;
vec vi;
cin >> vi.l >> vi.r;
vector<vec> v, a(n);
set<vec> st;
for (int i = 1; i < n; i++) {
vec vt;
cin >> vt.l >> vt.r;
a[i] = vec{vt.r - vi.l, 1, i}; //用1表示终点
v.push_back(vec{vt.l - vi.r, -1, i}); //-1表示起点
v.push_back(a[i]);
vi = vt;
}
for (ll i = 0, x; i < m; i++) {
cin >> x;
v.push_back(vec{x, 0, i + 1}); //0表示桥
}
sort(v.begin(), v.end());
for (auto it : v) {
if (it.r == -1) //遇到起点将该线段记入集合
st.insert(a[it.pos]);
else if (it.r == 1) //遇到终点就将线段删除
st.erase(a[it.pos]);
else if (st.size()) { //遇到桥,将set里最远的起点删除
int pos = st.begin()->pos;
ans[pos] = it.pos;
st.erase(st.begin());
}
}
bool f = 0;
for (int i = 1; i < n; i++)
if (!ans[i])
f = 1;
if (!f) {
cout << "Yes" << endl;
for (int i = 1; i < n; i++)
cout << ans[i] << ' ';
} else
cout << "No" << endl;
}
E.556E
很鬼畜的题目,也很直白
\(n\times n\)的巧克力,吃掉逆对角线下方的所有巧克力。然后每次在逆对角线上选择一个格子和一个方向,一直吃到被吃过的地方。问每次选择能吃多少个,\(q\)次询问。
思路:
- 选择一行或者一列吃之后,我们就直接记录每行最右边的格子位置和每列最下边的格子位置,这样就是\(O(1)\)的询问
- 选择第\(i\)行,那么就是该行\(U[y_i]=x_i\),列就是\(L[x_j]=y_i,j\in(1,n)\)
- 相应第\(i\)列也如此,该行\(L[x_i]=y_i\),列就是\(U[y_j]=x_i,j\in(1,n)\)
那么时间复杂度就是\(O(qn)\)显然超时。
下面考虑用线段树记录数据。众所周知,线段树的更新和查询都是\(O(\log{n})\)的
我们将询问的\(x\)和\(y\)都记录下来,离散化排序后用来进行线段树的建立,然后对于每次询问,每次查询更新就是\(O(\log{q})\)
总复杂度就是\(O(q\log{q})\)
注意这里的线段树需要打\(lazy~tag\)
官方题解只记录了\(x\),没太理解,于是我就按照自己的习惯写的
#if __cplusplus >= 201103L
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#else
#include <algorithm>
#include <bitset>
#include <cmath>
#include <iostream>
#include <map>
#include <string.h>
#include <vector>
#endif
using namespace std;
#define inf __INT_MAX__
#define enf INT_MIN
#define INF LLONG_MAX
#define ENF LLONG_MIN
const int MAXN = 4e5 + 10;
const double pi = acos(-1.0);
const double eps = 1e-6;
typedef long long ll;
typedef unsigned long long ull;
#define zhengfu(x) ((x > eps) - (x < -eps))
#define l(p) (p << 1)
#define r(p) (p << 1 | 1)
struct node {
ll d;
ll lazy;
ll L, R;
} treeL[MAXN << 2], treeU[MAXN << 2];
void built(node tree[], int p, int l, int r) {
tree[p].L = l, tree[p].R = r;
tree[p].lazy = 0;
tree[p].d = 0;
if (l != r) {
int mid = (l + r) >> 1;
built(tree, l(p), l, mid);
built(tree, r(p), mid + 1, r);
}
}
void push(node tree[], int p) {
tree[p].d = max(tree[p].d, tree[p].lazy);
if (tree[p].L != tree[p].R) {
tree[l(p)].lazy = max(tree[p].lazy, tree[l(p)].lazy);
tree[r(p)].lazy = max(tree[p].lazy, tree[r(p)].lazy);
}
}
int query(node tree[], int p, int k) {
push(tree, p);
if (k == tree[p].L && tree[p].L == tree[p].R)
return tree[p].d;
int mid = tree[p].L + tree[p].R >> 1;
return k > mid ? query(tree, r(p), k) : query(tree, l(p), k);
}
void update(node tree[], int p, int l, int r, int k) {
push(tree, p);
if (tree[p].L == l && tree[p].R == r) {
tree[p].lazy = k;
return;
}
int mid = tree[p].L + tree[p].R >> 1;
if (r <= mid)
update(tree, l(p), l, r, k);
else if (l > mid)
update(tree, r(p), l, r, k);
else
update(tree, l(p), l, mid, k), update(tree, r(p), mid + 1, r, k);
}
struct vec {
int x, y;
char ch;
};
int main() {
int n, q;
cin >> n >> q;
vector<vec> v(q); //x,y,u/l
vector<pair<int, char>> a; //用于离散的数组
for (auto &it : v) {
cin >> it.x >> it.y >> it.ch;
a.push_back(make_pair(it.x, it.ch));
a.push_back(make_pair(it.y, it.ch));
}
//离散
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end(), [](pair<int, char> b, pair<int, char> c) {
return b.first == c.first;
}),
a.end());
map<int, int> mp;
int len = a.size();
for (int i = 0; i < a.size(); i++)
mp[a[i].first] = i + 1;
int rootL = 1, rootU = 1;
built(treeL, rootL, 0, len + 1);
built(treeU, rootU, 0, len + 1);
for (auto it : v) {
int xx = mp[it.x], yy = mp[it.y];
if (it.ch == 'U') {
int ll = query(treeU, rootU, xx);
update(treeL, rootL, ll, yy, xx);
update(treeU, rootU, xx, xx, yy);
if (ll != 0)
printf("%d\n", a[yy - 1].first - a[ll - 1].first);
else
printf("%d\n", a[yy - 1].first);
} else {
int ll = query(treeL, rootL, yy);
update(treeU, rootU, ll, xx, yy);
update(treeL, rootL, yy, yy, xx);
if (ll != 0)
printf("%d\n", a[xx - 1].first - a[ll - 1].first);
else
printf("%d\n", a[xx - 1].first);
}
}
}
施法保佑
/**
爆ぜろリアル!弾けろシナプス!パニッシュメント・ディス・ワールド!
';!!!:`
.;%%%%$$$$%%%;.
.;$%;. :%;.
`||` :!.
.!: ::
:; .`.
'` ..
`` .
.. ..
..
`;||!:';|%$$$%%%$$%|;'.
'|%%%%%%%%%%%%%%%%%%%%%%%%%%%%|:.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$|:
.:!%%%%%%%%%%|!|%%%%$$&$$$%%%%%%%%%%%%%%%%|' `:'.
'!|%%%%%||%%%%%%%%%%%$&&&$%%%%%$$$%%%%%%%%%%%|'':':'.
`|%%%%%%%%%%%%%$%%%%%%%$&&&&$$%%%$$$%%%%%%%%%%%%|;:::'::':`
:%%%%%%$$%%%$$%%$%%%%%%%$&&&&&$$%%|%$%%%|!|%%%%%$!'::::;|!:'.
.;$%%%%%$$%%%$$%%$%%%%%%%%$&&&&&$$$%%$$$%%%!!%$%%%%!::!%%%%|;'.
.;%$%%%$$$%%%$$%%||%$$%%%%$$&&&&&&$$%%$$%%%%%%%$&&&$%$$$$%%%%|:.
;%%%%%$$$%%$&$%%!:!$$$%%%%$&$||&&&&$$%$$$%%%%%%$$$%%%%$$$$%%%|'
:%%$%%$$$$%$&&$%!`'|$&$%%%%$&|`.!&&&&$%$$$%%%%%%%$%%%%%%$$$$%%%;
`!%|%%%$&$%%$&$$|'.'|&&$%%%%$%|!'.:$&&&$$$$%%%%%%%%%%%%%%$$$$%%%|`
;%':%%$&&$%$&|!|'.`:|&&$%%%$$|'''``'%&&&$$$%%%%%%%%%%%%%%$&&$%%%%:
`;' ;%%$&$%%$%;;: .:!%$%%%$|` .. .!&&&$$$%%$%%%$%$$%$$%$&$%%%$;
'' .!%$&&$$%$;`:' `!%%%%:.... ....:$&$$$%$$%%$$$$$%$$%$&$%%%%;
.. .;%$&&&$%|:. ...;%|'..........'|$%%%$$%%$$&&$%$$%%%$%%%$;
;$$&&&$%!` .`....'`.... ......`!%%%$$%%$&&&$$&&$!!$%%%$:
'%$&&&&$!`. .`........``.......`!%%$$$%$&&&&$$&&$;;$%%%%'
'|$&&&&!``..```. ........`|@@|'....`:|%%$$%%$&&&&$$&&$':$%%%|`
`|$&&&&$' .``````'''::`..........``.:%%$&$%|'`!&&$$&&%':%%%%;.
;$$&&|;!:`........... .':`....`````!%$&&$%|;';&&&%|%%';%%%%:
'%$&$: ...................`''`...`:%%$&$$!`..!&&&$;`:;|%%%!`
;$&&%:..................... .':``!%$&&$;...:$&%'`;' ;%%%%:
.;$&&&$:..........`'............`!%$&&&;..'%&&! `!%%%:
.':|&&&|''`.............. ...'|$&&$||$&&&|` :|'``
.!%: `|$%|!:'`.........`:!%$&&&&&$;''. `.
.:!%$%||||||%%$$$$$$$$$%$%%$$$%%:.
`!%$%%%%%%%|||||||||||%|||||||%%%%%$%%%%|:
'%%%%%%%%%%%%||||||||!!|||||||||||%$$%%%%%%%%$%:
:%$$$%%%$%$$%||||||||!;%%||||||||%%%%%%%%%%%%%%%%|'
.;$%%%%$$$$$%%|||||%$$$$$%||||||||%$$%%%%%%%%%%%%%%'
.!%%%%%%$$%%$%%|||||;;%||||||||%$$&&|!%$$%%%$$$$$%;.
.!%%%%%%%%%%%%%%$%||%%%%%%%%%%%$&$$;`;%%%%%%%%$$!.
:%%%%%%%%%%%%%%||%%%%%%%%%%%$$$%%%%%%%%%%%%%|'
:%%%%%%%%%%$$%%%%%%%%%%%%%%%;`;%%%%%%%|:
.;%%%%%%%%%%%%%%%%%%%%%%%%%%%:..:|%%%!.
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|;:`
;$%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%'
`|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$;
.:!%$%%%%%%%%%%%%%%%%%%%%%%%%%%%%$!.
;!';%%%%%%%%%%%%%%%%%%%%%!:`. `|$%'
.;%%%%%%%%%%%||%%%%%%%%%|:';|%$%%%%%;.
.!%%%%%%%%%%%%$$%%%%%%%%%%%%%%%%%%%%%'
.!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$;.
.;%%%%%%%%%%%%$%%%%%%%%%%%%%%%%%%%%%%%'
;%$$%%%%%%%%$$$$%%%%%%%%%%%%%%%%%%%%%'
`|$&$%%%%%%$%$$$%%%%%%%%%%%%$%%%%%$&%%!`
:%$&$%%||%%%%$$%%%$%%%%%$$!:|%||%%$&$%%!`
**/