近年来最简单的一次 \(CSP\) 认证,\(3\) 个小时现场满分直接拿下。
1、
没啥好说的,直接开桶拿下。
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
template <class T>
inline T read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
return a = x * s;
}
int n, m;
map <int, int> g1;
map <int, int> g2;
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++){
int l; read(l);
bitset <N> vis(0);
for(int j = 1; j <= l; j++){
int x; read(x);
if(!vis[x]) g1[x]++, vis[x] = 1;
g2[x]++;
}
}
for(int i = 1; i <= m; i++){
cout << g1[i] << " " << g2[i] << endl;
}
return 0;
}
2、
注意题目要求,不区分大小写,所以全部变成大写或者小写就行。剩下的开个 \(map\) 秒杀。
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
template <class T>
inline T read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
return a = x * s;
}
int n, m;
set <string> s1, s2;
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++){
string s; cin >> s;
for(int j = 0; j < s.length(); j++){
if(s[j] >= 'A' && s[j] <= 'Z'){
s[j] = s[j] - 'A' + 'a';
}
}
s1.insert(s);
}
for(int i = 1; i <= m; i++){
string s; cin >> s;
for(int j = 0; j < s.length(); j++){
if(s[j] >= 'A' && s[j] <= 'Z'){
s[j] = s[j] - 'A' + 'a';
}
}
s2.insert(s);
}
int num1 = 0, num2 = 0;
for(auto it : s1){
auto it2 = s2.lower_bound(it);
if(it2 != s2.end() && (*it2) == it){
num1++;
}
}
for(auto it : s2){
s1.insert(it);
}
num2 = s1.size();
cout << num1 << endl << num2;
return 0;
}
3、
题目说啥就做啥。这个高斯消元的过程就是个递归,每一层记录左上角坐标。(感觉比直接抄板子还简单)
#include <bits/stdc++.h>
using namespace std;
#define N 210
template <class T>
inline T read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
return a = x * s;
}
int n, m;
int T;
double a[200][200], x[N];
const double eps = 1e-10;
inline int sgn(double x){
return (x > eps) - (x < -eps);
}
void gauss(int x, int y){ //瀹革缚绗傜憴?
// cout << x << " " << y << endl;
if(x >= n - 1 || y >= m - 1){
return ;
}
bool flag = 0;
for(int i = x; i < n; i++){
if(abs(a[i][y]) > eps) flag =1;
}
if(!flag) gauss(x, y + 1);
else{
if(abs(a[x][y]) <= eps){
for(int j = x + 1; j < n; j++){
if(abs(a[j][y]) > eps){
for(int k = y; k < m; k++){
swap(a[j][k], a[x][k]);
}
break;
}
}
}
for(int i = x + 1; i < n; i++){
double k = a[i][y] / a[x][y];
for(int j = y; j < m; j++){
a[i][j] -= k * a[x][j];
}
}
gauss(x + 1, y + 1);
}
return ;
}
int main(){
// freopen("hh.txt", "r", stdin);
read(T);
while(T--){
int n1;
read(n1);
set <string> s;
map <string, int> g;
int cnt = 0;
memset(a, 0, sizeof(a));
for(int i = 1; i <= n1; i++){
string t; cin >> t;
for(int j = 0; j < t.length(); ){
string tmp = "";
while(j < t.length() && isalpha(t[j])){
tmp.push_back(t[j]);
j++;
}
int x = 0;
while(j < t.length() && isdigit(t[j])){
x = x * 10 + (t[j] - '0');
j++;
}
s.insert(tmp);
if(!g.count(tmp)) g[tmp] = cnt++;
a[g[tmp]][i-1] = x;
}
}
n = cnt, m = n1;
gauss(0, 0);
int sum = 0;
for(int i = 0; i < n; i++){
bool flag = 0;
for(int j = 0; j < m; j++){
if(abs(a[i][j]) >= eps) flag = 1;
}
sum += flag;
}
if(sum >= n1) cout << "N" << endl;
else cout << "Y" << endl;
}
return 0;
}
4、
有史以来最简单的第四题。可以发现,我们只关心水滴的坐标大小关系,并不关心其具体值是多少。所以,直接用 \(set\) 存下所有的坐标,每次用 \(lowerbound\) 查找目标水滴,然后再将其左右两端进行更新。如果有多个待删水滴,则使用一个优先队列,按照下标排序即可。
#include <bits/stdc++.h>
using namespace std;
#define N 210
template <class T>
inline T read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
return a = x * s;
}
int c, m, n;
struct node{
int x, w;
bool operator < (const node &a) const{
return x < a.x;
}
bool operator == (const node &a) const{
return x == a.x && w == a.w;
}
} ;
set <node> s;
int main(){
// freopen("hh.txt", "r", stdin);
read(c), read(m), read(n);
for(int i = 1; i <= m; i++){
int x, w;
read(x), read(w);
s.insert((node){x, w});
}
// cout << "-------" << endl;
// for(auto it : s){
// cout << it.x << " " << it.w << endl;
// }
for(int i = 1; i <= n; i++){
int p; read(p);
auto it = s.lower_bound((node){p, 0});
auto tmp = *it;
s.erase(it);
tmp.w += 1;
s.insert(tmp);
set <int> q;
if(tmp.w >= 5){
q.insert(tmp.x); // 寰呯垎鐐哥殑
}
while(!q.empty()){
// cout << "-------" << endl;
int x = (*q.begin()); q.erase(q.begin());
// cout << x << endl;
auto it = s.lower_bound((node){x, 0});
if(it != s.begin()){
auto it1 = it;
it1--;
auto tmp1 = *it1;
s.erase(it1);
tmp1.w++;
s.insert(tmp1);
if(tmp1.w >= 5){
q.insert(tmp1.x);
}
}
auto it1 = it;
it1++;
if(it1 != s.end()){
auto tmp1 = *it1;
s.erase(it1);
tmp1.w++;
s.insert(tmp1);
if(tmp1.w >= 5){
q.insert(tmp1.x);
}
}
s.erase(it);
}
cout << s.size() << endl;
}
return 0;
}
5、
所有问题可以拆分成两个部分。先谈深度的维护问题。可以发现,需要经过的点的数量其实就是这个点现在的深度。又发现,我们可以单独维护其深度,因为每次合并可以视为将其所有子树的深度 \(-1\),所以求 \(dfn\),用树状数组或线段树维护即可。
接着是合并问题。首先考虑暴力合并形式,即每个点开一个 \(set\),合并时遍历所有的儿子,并将全部儿子的儿子插入当前点 \(set\)。超时的原因是合并点的次数过多。发现合并的内容是所有子树,所以考虑启发式合并。在合并时,我们不需要迁移重儿子的 \(set\)。为实现上述过程,考虑对每个点使用指针直接指向一个 \(set\)。修改时直接更改指针即可,避免了 \(set\) 的复制过程。
#include <bits/stdc++.h>
using namespace std;
#define N 500010
#define ll long long
template <class T>
inline T read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
return a = x * s;
}
struct node{
int u, v, next;
} t[N << 1];
int head[N];
int bian = 0;
inline void addedge(int u, int v){
t[++bian] = (node){u, v, head[u]}, head[u] = bian;
t[++bian] = (node){v, u, head[v]}, head[v] = bian;
return ;
}
set <int> *G[N];
set <int> s[N];
int n, m;
int fa[N];
ll d[N];
int a[N];
int deth[N], siz[N], son[N];
int dfn[N], rev[N], id = 0;
void dfs(int u, int father){
deth[u] = deth[father] + 1;
siz[u] = 1;
int maxn = -1;
for(int i = head[u] ; i; i = t[i].next){
int v = t[i].v;
if(v == fa[u]) continue;
dfs(v, u);
siz[u] += siz[v];
if(siz[v] > maxn){
maxn = siz[v];
son[u] = v;
}
}
return ;
}
void dfs2(int u, int tp){
dfn[u] = ++id;
rev[id] = u;
if(!son[u]) return ;
dfs2(son[u], son[u]);
for(int i = head[u]; i; i = t[i].next){
int v = t[i].v;
if(v == son[u] || v == fa[u]) continue;
dfs2(v, tp);
}
return ;
}
struct Segment_tree{
struct node{
int val;
int tag;
} t[N << 2];
#define lson (o<<1)
#define rson (o<<1|1)
inline void pushdown(int o, int l, int r){
if(t[o].tag){
int mid = l + r >> 1;
t[lson].tag += t[o].tag;
t[rson].tag += t[o].tag;
t[lson].val += t[o].tag * (mid - l + 1);
t[rson].val += t[o].tag * (r - mid);
t[o].tag = 0;
}
return ;
}
inline void pushup(int o){
t[o].val = t[lson].val + t[rson].val;
return ;
}
void build(int o, int l, int r){
if(l == r){
t[o].val = a[rev[l]];
return ;
}
int mid = l + r >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
pushup(o);
return ;
}
void update(int o, int l, int r, int in, int end, int k){
if(l > end || r < in) return ;
if(l >= in && r <= end){
t[o].val += k * (r - l + 1);
t[o].tag += k;
return ;
}
int mid = l + r >> 1;
pushdown(o, l, r);
update(lson, l, mid, in, end, k);
update(rson, mid + 1, r, in, end, k);
pushup(o);
return ;
}
int query(int o, int l, int r, int x){
if(l > x || r < x) return 0;
if(l == r && l == x){
return t[o].val;
}
int mid = l + r >> 1;
pushdown(o, l, r);
return query(lson, l, mid, x) + query(rson, mid + 1, r, x);
}
} tree;
signed main(){
read(n), read(m);
for(int i = 2; i <= n; i++){
int x; read(x);
fa[i] = x;
s[fa[i]].insert(i);
addedge(fa[i], i);
}
for(int i = 1; i <= n; i++){
read(d[i]);
G[i] = (&s[i]);
}
// G[0] = (&s[0]);
dfs(1, 0);
dfs2(1, 1);
for(int i = 1; i <= n; i++){
a[i] = deth[i];
}
tree.build(1, 1, n);
for(int i = 1; i <= m; i++){
int opt;
read(opt);
if(opt == 1){
int x; read(x);
if(G[x]->size() == 0){
cout << 0 << " " << d[x] << endl;
continue;
}
int maxn = -1;
for(auto it : (*G[x])){
d[x] += d[it];
if(siz[it] > maxn){
maxn = siz[it];
son[x] = it;
}
}
for(auto it : (*G[x])){
if(it == son[x]) continue;
for(auto it1 : (*G[it])){
G[son[x]]->insert(it1);
}
}
G[x] = G[son[x]];
tree.update(1, 1, n, dfn[x] + 1, dfn[x] + siz[x] - 1, -1);
cout << (*G[x]).size() << " " << d[x] << endl;
}
else{
int x; read(x);
cout << tree.query(1, 1, n, dfn[x]) << endl;
}
}
return 0;
}
标签:return,33,题解,++,int,while,read,CSP,getchar
From: https://www.cnblogs.com/wondering-world/p/18118023