https://vjudge.net/contest/173780

A.假设 Pt = i,则由Ppi = i得

Ppt = t = Pi

所以就有 if Pt = i then Pi = t

 #include <cstdio>
#include <algorithm> using namespace std; int n, a[]; int main() {
scanf("%d", &n);
if(n & ) puts("-1");
else {
for(int i = ;i <= n;i ++)
a[i] = i;
for(int i = ;i <= n;i += )
swap(a[i], a[i + ]);
for(int i = ;i <= n;i ++)
printf("%d ", a[i]);
}
}

B.

C.treap练手题,STL_set练手题,链表练手题

set用的不熟所以直接上的链表

排序后时间倒序来看的思路

 #include <cstdio>
#include <algorithm> using namespace std; typedef long long ll; const int maxn = ; int n, b[maxn]; ll ans; struct List{
int next, last;
}c[maxn]; struct node{
ll x;
int y;
bool operator < (const node &a) const {
return x < a.x;
}
}a[maxn]; int main() {
scanf("%d", &n);
for(int i = ;i <= n;i ++)
scanf("%lld", &a[i].x), a[i].y = i;
ans = a[].x;
a[].x = -1000000000000ll;
a[n + ].x = 1000000000000ll;
sort(a + , a + n + );
for(int i = ;i <= n;i ++) b[a[i].y] = i;
for(int i = ;i <= n;i ++) {
c[i].next = i + ;
c[i].last = i - ;
}
for(int i = n;i > ;i --) {
ans += min(a[b[i]].x - a[c[b[i]].last].x, a[c[b[i]].next].x - a[b[i]].x);
c[c[b[i]].last].next = c[b[i]].next;
c[c[b[i]].next].last = c[b[i]].last;
}
printf("%lld\n", ans);
return ;
}

D.边权给点,点修改和路径查询

直接上树剖+线段树,考场写狗

多组数据需要clear存边的vector,fa 和 son

修改的时候bel[i]找到第 i 条边权给的点

还要对应该点在线段树上的叶节点位置!

 #include <cstdio>
#include <vector>
#include <algorithm> using namespace std; const int maxn = ; int Case, n, M; struct Edge{
int v, w, num;
}; vector <Edge> edge[maxn]; char str[]; int a, b, tr[maxn << ]; int bel[maxn], siz[maxn], son[maxn], val[maxn]; int cnt, fa[maxn], dep[maxn], pos[maxn], dfn[maxn], top[maxn]; void dfs1(int u) {
siz[u] = ;
for(int v, i = ;i < edge[u].size();i ++) {
v = edge[u][i].v;
if(v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + ;
val[v] = edge[u][i].w;
bel[edge[u][i].num] = v;
dfs1(v), siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
} void dfs2(int u, int tp) {
top[u] = tp, pos[u] = ++ cnt, dfn[cnt] = u;
if(son[u]) dfs2(son[u], tp);
for(int v, i = ;i < edge[u].size();i ++) {
v = edge[u][i].v;
if(v != fa[u] && v != son[u])
dfs2(v, v);
}
} void change(int i, int x) {
i = pos[i];
for(tr[i += M] = x, i >>= ;i;i >>= )
tr[i] = max(tr[i << ], tr[i << | ]);
} int mmax(int s, int t) {
int res = -;
for(s += M - , t += M + ;s ^ t ^ ;s >>= , t >>= ) {
if(~ s & ) res = max(res, tr[s ^ ]);
if( t & ) res = max(res, tr[t ^ ]);
}
return res;
} void query(int u, int v) {
int fu = top[u], fv = top[v], res = -;
while(fu != fv) {
if(dep[fu] < dep[fv]) swap(u, v), swap(fu, fv);
res = max(res, mmax(pos[fu], pos[u]));
u = fa[fu], fu = top[u];
}
if(u == v) printf("%d\n", res);
else {
if(dep[u] < dep[v]) swap(u, v);
printf("%d\n", max(res, mmax(pos[v] + , pos[u])));
}
} int main() {
//freopen("test.txt","r",stdin);
val[] = -;
int u, v, w;
scanf("%d", &Case);
while(Case --) {
cnt = ;
scanf("%d", &n);
for(int i = ;i <= n;i ++) edge[i].clear(), fa[i] = son[i] = ;
for(int i = ;i < n;i ++) {
scanf("%d %d %d", &u, &v, &w);
edge[u].push_back((Edge){v, w, i});
edge[v].push_back((Edge){u, w, i});
}
dfs1(), dfs2(, );
for(M = ;M < n + ; M <<= );
for(int i = ;i <= n;i ++) tr[i + M] = val[dfn[i]];
for(int i = n + ;i <= M + ;i ++) tr[i + M] = val[];
for(int i = M;i;i --) tr[i] = max(tr[i << ], tr[i << | ]);
while(scanf("%s", str), str[] != 'D') {
if(str[] == 'C') scanf("%d %d", &a, &b), change(bel[a], b);
else scanf("%d %d", &a, &b), query(a, b);
}
puts("");
}
}

E.考场上脑补出来一个正解,可惜只差了一步

两个单调队列,一增一减,从前向后扫

当扫到某个位置,最大差距 > R 时

踢出两个队列中位置最靠前的元素直至差距 <= R

如果这是最大差距 >= L 则更新答案即可

时间复杂度O(n),别人说这是个做过的RMQ啊...

 #include <cstdio>
#include <algorithm> using namespace std; const int maxn = ; int n, x, y, m, a[maxn], q1[maxn], q2[maxn]; int l1, r1, l2, r2, t; int main() {
while(scanf("%d %d %d", &n, &x, &y) != EOF) {
for(int i = ;i <= n;i ++)
scanf("%d", &a[i]);
m = t = , l1 = l2 = , r1 = r2 = ;
for(int i = ;i <= n;i ++) {
while(l1 <= r1 && a[i] > a[q1[r1]]) r1 --;
q1[++ r1] = i;
while(l2 <= r2 && a[i] < a[q2[r2]]) r2 --;
q2[++ r2] = i;
while(l1 <= r1 && l2 <= r2 && a[q1[l1]] > a[q2[l2]] + y) {
if(q1[l1] < q2[l2]) t = q1[l1 ++];
else t = q2[l2 ++];
}
if(l1 <= r1 && l2 <= r2 && a[q1[l1]] >= a[q2[l2]] + x) m = max(m, i - t);
}
printf("%d\n", m);
}
return ;
}

F.就是枚举min,然后单调队列求出左右拓展多远就好了

 #include <cstdio>

 const int maxn = ;

 int l = , r, q[maxn];

 int L, R, n, a[maxn], b[maxn], c[maxn];

 long long ans = -, tmp, s[maxn];

 int main() {
scanf("%d", &n);
for(int i = ;i <= n;i ++)
scanf("%d", &a[i]), s[i] = a[i] + s[i - ];
for(int i = ;i <= n;i ++) {
while(l <= r && a[i] < a[q[r]]) b[q[r]] = i - q[r], r --;
q[++ r] = i;
}
while(l <= r) b[q[r]] = n + - q[r], r --;
l = , r = ;
for(int i = n;i;i --) {
while(l <= r && a[i] < a[q[r]]) c[q[r]] = q[r] - i, r --;
q[++ r] = i;
}
while(l <= r) c[q[r]] = q[r], r --;
for(int i = ;i <= n;i ++) {
tmp = (s[i + b[i] - ] - s[i - c[i]]) * a[i];
if(tmp > ans) ans = tmp, L = i - c[i] + , R = i + b[i] - ;
}
printf("%lld\n%d %d", ans, L ,R);
return ;
}

G.开始没看清题发现大家都会写区间众数?

连续的相同...线段树傻逼题

 #include <cstdio>
#include <algorithm> using namespace std; const int maxn = ; struct node{
int ls, rs, lc, rc, mm;
}tr[maxn << ]; int n, m, c[maxn]; node operator +(const node &a, const node &b) {
node res;
res.ls = a.ls;
res.lc = a.lc;
res.rs = b.rs;
res.rc = b.rc;
res.mm = max(a.mm, b.mm);
if(a.rc == b.lc) {
res.mm = max(res.mm, a.rs + b.ls);
if(a.lc == a.rc) res.ls += b.ls;
if(b.lc == b.rc) res.rs += a.rs;
}
return res;
} void build(int o, int l, int r) {
if(l == r) {
tr[o] = (node){, , c[r], c[r], };
return;
}
int mid = (l + r) >> ;
build(o << , l, mid);
build(o << | , mid + , r);
tr[o] = tr[o << ] + tr[o << | ];
} node ask(int o, int l, int r, int s, int t){
if(s <= l && r <= t) return tr[o];
int mid = (l + r) >> ;
if(t <= mid) return ask(o << , l, mid, s, t);
else if(s > mid) return ask(o << | , mid + , r, s, t);
else return ask(o << , l, mid, s, t) + ask(o << | , mid + , r, s, t);
} int main() {
int a, b;
while(scanf("%d %d", &n, &m), n != ) {
for(int i = ;i <= n;i ++)
scanf("%d", &c[i]);
build(, , n);
//printf("%d %d %d\n",tr[1].mm,tr[6].rc, tr[7].lc);
while(m --) {
scanf("%d %d", &a, &b);
printf("%d\n", ask(, , n, a, b).mm);
}
}
}

H.

I.无修改查询树上路径和,随便做啦

dis[u] + dis[v] - dis[lca] * 2

我直接上的bfs树剖求lca

 #include <cstdio>
#include <vector>
#include <algorithm> using namespace std; const int maxn = ; struct Edge{
int v, w;
}; vector <Edge> edge[maxn]; int Case, n, m, a, b, c, dis[maxn]; int l, r, q[maxn], siz[maxn], son[maxn]; int cnt, fa[maxn], dep[maxn], top[maxn]; int lca(int u, int v) {
int fu = top[u], fv = top[v];
while(fu != fv) {
if(dep[fu] < dep[fv]) swap(u, v), swap(fu, fv);
u = fa[fu], fu = top[u];
}
return dep[u] < dep[v] ? u : v;
} int main() {
int u, v, w;
scanf("%d", &Case);
while(Case --) {
scanf("%d %d", &n, &m);
for(int i = ;i < n;i ++) {
scanf("%d %d %d", &u, &v, &w);
edge[u].push_back((Edge){v, w});
edge[v].push_back((Edge){u, w});
}
l = r = , q[++ r] = ;
while(l <= r) {
u = q[l ++];
siz[u] = , son[u] = top[u] = ;
for(int i = ;i < edge[u].size();i ++) {
v = edge[u][i].v;
if(v == fa[u]) continue;
fa[v] = u, q[++ r] = v, dep[v] = dep[u] + , dis[v] = dis[u] + edge[u][i].w;
}
}
for(int i = n;i > ;i --) {
siz[fa[q[i]]] += siz[q[i]];
if(!son[fa[q[i]]] || siz[son[fa[q[i]]]] < siz[q[i]]) son[fa[q[i]]] = q[i];
}
for(int i = ;i <= n;i ++) {
u = q[i];
if(son[fa[u]] == u) top[u] = top[fa[u]];
else top[u] = u;
}
while(m --) {
scanf("%d %d", &a, &b);
c = lca(a, b);
printf("%d\n", dis[a] - dis[c] - dis[c] + dis[b]);
}
}
}

J.裸树状数组

 #include <cstdio>

 const int maxn = ;

 int c[maxn], a[maxn];

 int Case, n, x, y;

 char str[];

 int lowbit(int x) {
return (x & (-x));
} int ask(int i) {
int res = ;
while(i > ) res += c[i], i -= lowbit(i);
return res;
} void add(int i, int x) {
while(i <= n) c[i] += x, i += lowbit(i);
} int main() {
//freopen("test.txt", "r", stdin);
scanf("%d", &Case);
for(int tt = ;tt <= Case;tt ++) {
printf("Case %d:\n", tt);
scanf("%d", &n);
for(int i = ;i <= n;i ++)
scanf("%d", &a[i]), a[i] += a[i - ];
while(scanf("%s", str), str[] != 'E') {
scanf("%d %d", &x, &y);
if(str[] == 'Q') printf("%d\n", ask(y) - ask(x - ) + a[y] - a[x - ]);
else add(x, y * (str[] == 'A' ? : -));
}
for(int i = ;i <= n;i ++) c[i] = ;
}
return ;
}

K.区间加和区间求和,差分树状数组除非有封装好的板子

不然现场还是只能写线段树

 #include <cstdio>
#include <algorithm> using namespace std; typedef long long ll; const int maxn = ; int n, m, d[maxn]; char str[]; int a, b, c; ll s[maxn]; struct node{
ll lazy, sum;
}tr[maxn << ]; void pushup(int o) {
tr[o].sum = tr[o << ].sum + tr[o << | ].sum;
} void pushdown(int o, int l, int r) {
if(!tr[o].lazy) return;
int mid = (l + r) >> ;
tr[o << ].sum += tr[o].lazy * (mid - l + );
tr[o << | ].sum += tr[o].lazy * (r - mid);
tr[o << ].lazy += tr[o].lazy;
tr[o << |].lazy += tr[o].lazy;
tr[o].lazy = ;
} void add(int o, int l, int r, int s, int t, int x) {
if(l != r) pushdown(o, l, r);
if(s <= l && r <= t) {
tr[o].lazy += x;
tr[o].sum += 1ll * x * (r - l + );
return;
}
int mid = (l + r) >> ;
if(s <= mid) add(o << , l, mid, s, t, x);
if(mid < t) add(o << | , mid + , r, s, t, x);
pushup(o);
} ll query(int o, int l, int r, int s, int t) {
if(l != r) pushdown(o, l, r);
if(s <= l && r <= t) return tr[o].sum;
ll res = ;
int mid = (l + r) >> ;
if(s <= mid) res += query(o << , l, mid, s, t);
if(mid < t) res += query(o << | , mid + , r, s, t);
pushup(o);
return res;
} int main(int argc, char const *argv[]){
scanf("%d %d", &n, &m);
for(int i = ;i <= n;i ++)
scanf("%d", &d[i]), s[i] = s[i - ] + d[i];
while(m --) {
scanf("%s %d %d", str, &a, &b);
if(str[] == 'Q') printf("%lld\n", query(, , n, a, b) + s[b] - s[a - ]);
else scanf("%d", &c), add(, , n, a, b, c);
}
return ;
}

L.vector会TLE改邻接表能过...***

dfs序 + 树状数组

 #include <cstdio>

 const int maxn = ;

 int n, m, q, a[maxn], c[maxn], st[maxn], en[maxn];

 int tot, head[maxn], to[maxn], next[maxn];

 void ade(int x, int y) {
to[++ tot] = y, next[tot] = head[x], head[x] = tot;
} int lowbit(int x) {
return (x & (-x));
} int ask(int i) {
int res = ;
while(i > ) res += c[i], i -= lowbit(i);
return res;
} void add(int i, int x) {
while(i <= n) c[i] += x, i += lowbit(i);
} void dfs(int x, int f) {
a[x] = , st[x] = ++ m;
for(int y, i = head[x];i;i = next[i]) {
y = to[i];
if(y == f) continue;
dfs(y, x);
}
en[x] = m;
} char str[]; int x; int main() {
scanf("%d", &n);
for(int u, v, i = ;i < n;i ++) {
scanf("%d %d", &u, &v);
ade(u, v), ade(v, u);
}
dfs(, );
scanf("%d", &q);
while(q --) {
scanf("%s %d", str, &x);
if(str[] == 'Q') printf("%d\n", ask(en[x]) - ask(st[x] - ) + en[x] - st[x] + );
else {
if(a[x]) add(st[x], -), a[x] = ;
else add(st[x], ), a[x] = ;
}
}
return ;
}

bupt summer training for 16 #5 ——数据结构的更多相关文章

  1. bupt summer training for 16 #8 ——字符串处理

    https://vjudge.net/contest/175596#overview A.设第i次出现的位置左右端点分别为Li,Ri 初始化L0 = 0,则有ans = sum{ (L[i] - L[ ...

  2. bupt summer training for 16 #7 ——搜索与DP

    https://vjudge.net/contest/174962#overview A.我们发现重点在于x,y只要累加就ok了 在每个x上只有上下两种状态,所以可以记忆化搜索 f[0/1][i]表示 ...

  3. bupt summer training for 16 #6 ——图论

    https://vjudge.net/contest/174020 A.100条双向边,每个点最少连2个边 所以最多100个点,点的标号需要离散化 然后要求恰好经过n条路径 快速幂,乘法过程就是flo ...

  4. bupt summer training for 16 #4 ——数论

    https://vjudge.net/contest/173277#overview A.平方差公式后变为 n = (x + y)(x - y) 令 t = x - y ,变成 n = (t + 2x ...

  5. bupt summer training for 16 #3 ——构造

    https://vjudge.net/contest/172464 后来补题发现这场做的可真他妈傻逼 A.签到傻逼题,自己分情况 #include <cstdio> #include &l ...

  6. bupt summer training for 16 #2 ——计算几何

    https://vjudge.net/contest/171368#overview A.一个签到题,用叉积来判断一个点在一条线的哪个方向 可以二分,数据范围允许暴力 #include <cst ...

  7. bupt summer training for 16 #1 ——简单题目

    D.What a Mess 给n个数,求其中能满足 a[i] % a[j] == 0 的数对之和 n = 1W,max_ai = 100W 不是很大,所以就直接筛就可以了 计算可得最高复杂度 < ...

  8. 数据结构和算法(Golang实现)(16)常见数据结构-字典

    字典 我们翻阅书籍时,很多时候都要查找目录,然后定位到我们要的页数,比如我们查找某个英文单词时,会从英语字典里查看单词表目录,然后定位到词的那一页. 计算机中,也有这种需求. 一.字典 字典是存储键值 ...

  9. 【Android Developers Training】 16. 暂停和恢复一个Activity

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. 如何理解Apache License, Version 2.0(整理)

    如何理解Apache License, Version 2.0(整理) 问题: 最近看到apache发布了2.0版本的License.而且微软也以此发布了部分源代码.我对OpenSource不是特熟, ...

  2. 华为FusionSphere概述——计算资源、存储资源、网络资源的虚拟化,同时对这些虚拟资源进行集中调度和管理

    华为FusionSphere概述 FusionSphere是华为自主知识产权的云操作系统,集虚拟化平台和云管理特性于一身,让云计算平台建设和使用更加简捷,专门满足企业和运营商客户云计算的需求.华为云操 ...

  3. bzoj 1022 小约翰的游戏John

    题目大意: n堆石子,两个人轮流取石子,每个人取的时候,可以随意选择一堆石子 在这堆石子中取走任意多的石子,但不能一粒石子也不取,取到最后一粒石子的人算输 思路: 首先当每堆石子数都为1时,偶数为先手 ...

  4. 40. combo的displayField和valueField属性

    转自:https://xsl2007.iteye.com/blog/773464 下拉框combo可以设置displayField和valueField属性,这两个值值相当于Java中的map,一个键 ...

  5. PCB 围绕CAM自动化,打造PCB规则引擎

    AutoCAM自动化平台,前端管理订单,而后端执行任务,前端UIl界面有板厚,铜厚,板材,表面处理,层数等信息,而这些信息并不是后端最终所需要的信息后.拿钻孔补偿来说,后端需要的是钻孔补偿值,但前端并 ...

  6. 湖南集训Day1

    难度 不断网:☆☆☆ 断网:☆☆☆☆ /* 卡特兰数取模 由于数据范围小,直接做. 考试时断网.忘记卡特兰数公式,推错了只有5分. 数学公式要记别每次都现用现搜!!! */ #include<i ...

  7. C# 的反射和映射

    最近想研究一下反射,先上网找了找资料,几乎大部分都是照抄MSDN的内容,生涩难懂,几乎没说,又找了找,发现一些强人的实例解析,才稍微有了 点门道,个人感觉,反射其实就是为了能够在程序运行期间动态的加载 ...

  8. javascript中for...in和for...of的区别

    for...of循环是ES6引入的新的语法. for...in遍历拿到的x是键(下标).而for...of遍历拿到的x是值,但在对象中会提示不是一个迭代器报错.例子如下: let x; let a = ...

  9. 【洛谷4396/BZOJ3236】[AHOI2013]作业(莫队+分块/树状数组/线段树)

    题目: 洛谷4396 BZOJ3236(权限) 这题似乎BZOJ上数据强一些? 分析: 这题真的是--一言难尽 发现题面里没说权值的范围,怕出锅就写了离散化.后来经过面向数据编程(以及膜神犇代码)知道 ...

  10. 【转】Linux账号管理之useradd

    转自:http://www.jb51.net/article/45848.htm Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然 ...