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. unpe13e 学习备忘1

    转其他地方.  http://blog.sina.com.cn/s/blog_a43aba560101a2s5.html 运行书本中的程序.1,首先,下载源码:unpv13e.tar.gz2,然后,编 ...

  2. Java 下的函数对象

    1. 举例 如我们要创建一个对大小写敏感的,按照字母序排序的 Set,我们需要向 Set 的构造器传入 String.CASE_INSENTIVE_ORDER 的比较器: Set<String& ...

  3. [luogu4735]最大异或和

    https://zybuluo.com/ysner/note/1238161 题面 给定一个初始长度为\(N\)的非负整数序列\(\{a\}\). 有\(m\)个操作,操作分为两种: 在序列末尾加一个 ...

  4. UVALive 4671 K-neighbor substrings 巧用FFT

    UVALive4671   K-neighbor substrings   给定一个两个字符串A和B B为模式串.问A中有多少不同子串与B的距离小于k 所谓距离就是不同位的个数. 由于字符串只包含a和 ...

  5. vs打开wixproj后缀文件

    1.在正常情况下vs是无法打开wixproj工程的,能打开也只能是以记事本方式打开该文件本身 2.所以此时需要下载wixtool,安装后即可打开上述类型文件 3.最好也安装好vs对应版本的扩展包 4. ...

  6. PCB OD工具破解实例应用

    以下破解Genesis为例,对OD工具使用进行实例讲解 工具简单 介绍下下载地址: OD工具:是一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring 3级调试器, 是为当今最为流行的 ...

  7. input如何去掉边框

    outline: none; border:solid 0px; 两个属性,ok.

  8. 【转】Java中特殊的String类型

    Java中String是一个特殊的包装类数据有两种创建形式: String s = "abc"; String s = new String("abc"); 第 ...

  9. Winform中Treeview控件失去焦点,将选择的节点设置为高亮显示 (2012-07-16 13:47:07)转载▼

    Winform中Treeview控件失去焦点,将选择的节点设置为高亮显示 (2012-07-16 13:47:07)转载▼标签: winform treeview drawnode Treeview控 ...

  10. Android视频截图

    本文介绍如何获取视频中某个时间点的数据 调用以下方法即可,特别注意,在获取图片时的参数单位为微秒,不是毫秒 如果错用了毫秒会一直获取第一帧的画面 /** * 获取某个时间点的帧图片 * * @para ...