zoukankan      html  css  js  c++  java
• # BUPT2017 springtraining(16) #2 ——基础数据结构

题目在这里

A.似乎是个并查集+？？？

B.10W的范围，似乎可以暴力来一发二分+sort？

但我猜正解可以O(nlogn)？

C.单调队列入门题目

```#include <cstdio>

int n, m, a[1111111], ans1[1111111], ans2[1111111];

struct queue_1 {
int q[1111111];
int l, r;
queue_1(): l(1), r(0) {}
int front() {
return q[l];
}
void push(int i) {
while(l <= r && q[l] + m <= i)   l ++;
while(r >= l && a[i] <= a[q[r]]) r --;
q[++ r] = i;
}
}q1;

struct queue_2 {
int q[1111111];
int l, r;
queue_2(): l(1), r(0) {}
int front() {
return q[l];
}
void push(int i) {
while(l <= r && q[l] + m <= i)   l ++;
while(r >= l && a[i] >= a[q[r]]) r --;
q[++ r] = i;
}
}q2;

void getint(int &x) {
x = 0;
static int c, f;
while(c = getchar(), (c < '0' || c > '9') && c != '-');
if(c != '-') x = c - '0', f = 0;
else f = 1, x = 0;
while(c = getchar(), c >= '0'&&c <= '9') x = x * 10 + c - '0';
if(f) x = -x;
}

int main() {
getint(n), getint(m);
for(int i = 1;i < m;i ++) getint(a[i]), q1.push(i), q2.push(i);
for(int i = m;i <= n;i ++)
getint(a[i]), q1.push(i), q2.push(i),
ans1[++ ans1[0]] = a[q1.front()], ans2[++ ans2[0]] = a[q2.front()];
for(int i = 1;i <= ans1[0];i ++) printf("%d ", ans1[i]);puts("");
for(int i = 1;i <= ans2[0];i ++) printf("%d ", ans2[i]);
return 0;
}```
View Code

我怎么就脑子抽了写了个极丑的封装呢

注意选择C++，G++会超时

D.简单的单点修改+区间查询max

线段树即可，据说这题还能有树状数组的骚操作？

比较懒，写了两个好写一点的

分块

```#include <cstdio>

int n, m, siz;
int a[200010], mmax[500];

int max(int x, int y){
return x > y ? x : y;
}

int main() {
int x, y, z;
char str[3];
while(scanf("%d %d", &n, &m) != EOF) {
for(siz = 1;siz * siz < n;siz ++);
for(int i = 0;i <= n / siz;i ++) mmax[i] = 0;
for(int i = 0;i < n;i ++)
scanf("%d", &a[i]), mmax[i / siz] = max(mmax[i / siz], a[i]);
while(m --) {
scanf("%s %d %d", str, &x, &y);
if(str[0] == 'Q') {
z = 0, x --, y --;
if(x / siz == y / siz) {
for(int i = x;i <= y;i ++)
z = max(z, a[i]);
}
else {
for(int i = x;i < x / siz * siz + siz;i ++)
z = max(z, a[i]);
for(int i = y / siz * siz;i <= y;i ++)
z = max(z, a[i]);
for(int i = x / siz + 1;i < y / siz;i ++)
z = max(z, mmax[i]);
}
printf("%d
", z);
}
else {
x --, a[x] = y, mmax[x / siz] = 0;
for(int i = x / siz * siz;i < x / siz * siz + siz;i ++)
mmax[i / siz] = max(mmax[i / siz], a[i]);
}
}
}
}```
View Code

zkw线段树

```#include <cstdio>

int n, m, M;
int tr[600010];

int max(int x, int y){
return x > y ? x : y;
}

int main() {
int x, y, z;
char str[3];
while(scanf("%d %d", &n, &m) != EOF) {
for(M = 1;M < n + 2;M <<= 1);
for(int i = M + 1;i <= M + n;i ++) scanf("%d", &tr[i]);
for(int i = M + n + 1;i <= (M << 1);i ++) tr[i] = 0;
for(int i = M;i >= 1;i --) tr[i] = max(tr[i << 1], tr[i << 1 | 1]);
while(m --) {
scanf("%s %d %d", str, &x, &y);
if(str[0] == 'Q') {
z = 0;
for(int s = x + M - 1, t = y + M + 1;s ^ t ^ 1;s >>= 1, t >>= 1) {
if(~s & 1) z = max(z, tr[s ^ 1]);
if( t & 1) z = max(z, tr[t ^ 1]);
}
printf("%d
", z);
}
else {
for(tr[x += M] = y, x >>= 1;x;x >>= 1)
tr[x] = max(tr[x << 1], tr[x << 1 | 1]);
}
}
}
}```
View Code

多组数据的话，基本注意每次都clear一下就好了

另外分块更滋磁下标从0开始计算

但是如果题目明确标号从1-n就要另外注意一下了

E.一个简单的队列套队列，代码供参考

```#include <queue>
#include <cstdio>
#include <iostream>

#define rep(i, j, k) for(int i = j;i <= k;i ++)

using namespace std;

queue <int> q, a[1111];

int n, bel[1111111];

int main() {
int m, x, t = 0;
char str[10];
ios::sync_with_stdio(false);
while(cin >> n, n != 0) {
printf("Scenario #%d
", ++ t);
rep(i, 1, n) {
cin >> m;
rep(j, 1, m) cin >> x, bel[x] = i;
}
while(cin >> str, str[0] != 'S') {
if(str[0] == 'E') {
cin >> x;
if(!a[bel[x]].size()) q.push(bel[x]);
a[bel[x]].push(x);
}
else {
printf("%d
", a[q.front()].front());
a[q.front()].pop();
if(!a[q.front()].size()) q.pop();
}
}
while(!q.empty()) q.pop();
rep(i, 1, n) while(!a[i].empty()) a[i].pop();
puts("");
}
}```
View Code

F.无修改区间最值问题，直接上线段树(我写的zkw

```#include <cstdio>

int n, m, M, tr[2][666666];

int min(int x, int y) {
return x < y ? x : y;
}

int max(int x, int y) {
return x > y ? x : y;
}

int main() {
int s, t, r, l;
scanf("%d %d", &n, &m);
for(M = 1;M < n + 2; M <<= 1);
for(int i = M + 1;i <= M + n;i ++) scanf("%d", &tr[0][i]), tr[1][i] = tr[0][i];
for(int i = M + n + 1;i <= M << 1;i ++) tr[1][i] = 6666666;
for(int i = M;i;i --)
tr[0][i] = max(tr[0][i << 1], tr[0][i << 1 | 1]),
tr[1][i] = min(tr[1][i << 1], tr[1][i << 1 | 1]);
while(m --) {
scanf("%d %d", &s, &t), r = 0, l = 6666666;
for(s += M - 1, t += M + 1;s ^ t ^ 1;s >>= 1, t >>= 1) {
if(~ s & 1) r = max(r, tr[0][s ^ 1]), l = min(l, tr[1][s ^ 1]);
if(  t & 1) r = max(r, tr[0][t ^ 1]), l = min(l, tr[1][t ^ 1]);
}
printf("%d
", r - l);
}
return 0;
}```
View Code

G.并查集+堆的启发式合并

总之手写堆大概只是用来理解其原理的

平时写题又不卡常数还是priority_queue大法好啊

顶多撸个简单的 '<' 重载美滋滋

```#include <queue>
#include <cstdio>

using std::queue;
using std::priority_queue;

priority_queue <int> q[100010];

int n, m, f[100010], a[100010];

void swap(int &x, int &y) {
x ^= y,  y ^= x, x ^= y;
}

int find_(int x) {
if(f[x] != x) return f[x] = find_(f[x]);
return x;
}

int main() {
int x, y, z;
while(scanf("%d", &n) != EOF) {
for(int i = 1;i <= n;i ++)
f[i] = i, scanf("%d", &a[i]), q[i].push(a[i]);
scanf("%d", &m);
while(m -- ){
scanf("%d %d", &x, &y);
x = find_(x), y = find_(y);
if(x == y) puts("-1");
else {
if(q[x].size() < q[y].size()) swap(x, y);
z = q[x].top(), q[x].pop(), q[x].push(z >> 1);
z = q[y].top(), q[y].pop(), q[y].push(z >> 1);
f[y] = x;
while(!q[y].empty()) q[x].push(q[y].top()), q[y].pop();
printf("%d
", q[x].top());
}
}
for(int i = 1;i <= n;i ++)
while(!q[i].empty()) q[i].pop();
}
}```
View Code

H.把如何锯木头看成如何拼木头

就是个石子合并问题，或者说哈夫曼树构造问题

```#include <iostream>
#include <queue>

#define rep(i, j, k) for(int i = j;i <= k;i ++)

#define rev(i, j, k) for(int i = j;i >= k;i --)

using namespace std;

typedef long long ll;

priority_queue <ll, vector<ll>, greater<ll> > q;

ll ans, a, w;

int n;

int main() {
ios::sync_with_stdio(false);
cin >> n;
rep(i, 1, n) cin >> a, q.push(a);
rep(i, 2, n) w = q.top(), q.pop(), w += q.top(), q.pop(), ans += w, q.push(w);
cout << ans;
return 0;
}```
View Code

I.很裸的并查集

我们用 i 和 i + n 来代表虫 i 的两个相反性别

而如果有 x 和 y 交配，那么显然有

x 和 y + n 为同一性别

y 和 x + n 为同一性别

即 union(x, y + n), union(y, x + n)

所以最终在同一集合中的小虫都必须是同一性别

而如果存在 i，满足 i 和 i + n 在同一个集合中

那么显然存在矛盾了

```#include <cstdio>

int Case, n, m, f[4444];

int find_(int x) {
if(f[x] != x) return f[x] = find_(f[x]);
return x;
}

void union_(int x, int y) {
x = find_(x), y = find_(y);
if(x != y) f[y] = x;
}

int main() {
int x, y, ans = 1;
scanf("%d", &Case);
for(int t = 1;t <= Case;t ++) {
ans = 1, printf("Scenario #%d:
", t);
scanf("%d %d", &n, &m);
for(int i = 1;i <= n;i ++) f[i] = i, f[i + n] = i + n;
for(int i = 1;i <= m;i ++) {
scanf("%d %d", &x, &y);
union_(x, y + n), union_(x + n, y);
}
for(int i = 1;i <= n;i ++)
if(find_(i) == find_(i + n)) {
ans = 0;
break;
}
puts(ans ? "No suspicious bugs found!
" : "Suspicious bugs found!
");
}
return 0;
}```
View Code

J.看图没看题，可能是个单调队列？

K.太长没看

L.对区间们排个序，然后就是个简单的线段树？

M.树状数组查个逆序对啥的

那个不断往后放的操作其实就那样吧

减一下加一下它对逆序对数造成的影响就行了

```#include <cstdio>

int n, a[5555], c[5555];

int lowbit(int x) {
return x & (-x);
}

while(i <= n) c[i] ++, i += lowbit(i);
}

int ret = 0;
while(i > 0) ret += c[i], i -= lowbit(i);
return ret;
}

long long sum, ans;

int main() {
while(scanf("%d", &n) != EOF) {
sum = 0;
for(int i = 1;i <= n;i ++) c[i] = 0;
for(int i = 1;i <= n;i ++)
ans = sum;
for(int i = 1;i < n;i ++) {
sum += n - 1 - ask(a[i] - 1) * 2;
if(sum < ans) ans = sum;
}
printf("%lld
", ans);
}
}```
View Code

N.map随便做，读入有点恶心就是了

我用的getline，因为直接cin读入string类型会忽略换行和空格

而getline就能读入一行，读入的一行为空的话，会有s[0] = ''

也就是读进来一个空串而不会被直接忽略这个空行

```#include <map>
#include <iostream>

using namespace std;

map <string, string> p;

string s1, s2, s;

int main() {
int i;
ios::sync_with_stdio(false);
while(getline(cin, s), s[0] != '') {
i = 0, s1 = "", s2 = "";
while(s[i] != ' ')  s1 += s[i ++];i ++;
while(s[i] != '') s2 += s[i ++];
p[s2] = s1;
}
while(cin >> s) {
if(p[s] != "") cout << p[s] << endl;
else cout << "eh
";
}
return 0;
}```
View Code

O.很裸的主席树，离线做有点费脑子？

P.简单题目，自己手算循环节即可

```#include<iostream>

using namespace std;

int a[] = {0, 1, 4, 6, 5,  2};

int main() {
int t;
long long n;
cin >> t;
while(t--) cin >> n, cout << a[n % 6] << endl;
return 0;
}```
View Code=

题后话:

poj真的很老旧了啊

1.bits/stdc++.h 这个全能库不支持

2.ios::sync_with_stdio(false)

取消cin与stdio的同步都不支持

就是加了这句话依旧是cin的速度...

3.G++和C++两个选项很迷

编译标准和运行时间都会有差别...

一个编译过了另一个可能编译不过...

一个提交超时另一个可能就通过了...

• 相关阅读:
Jquery 基本知识(一)
Json对象与Json字符串互转(转载)
一道面试题：StringBuffer a=new StringBuffer ("A"); StringBuffer b=new StringBuffer (StringBuffer线程安全 StringBuilder线程不安全)
MySql数据库连接池专题
linux 负载均衡配置 keepalive lvs 使用nginx转发 CentOS7 搭建LVS+keepalived负载均衡
linux 安装nginx -查看 linux的环境变量
生产者/消费者模式(阻塞队列)
线程与进程的区别
Linux中Apache+Tomcat+JK实现负载均衡和群集的完整过程