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. Java多线程相关的常用接口

    Runnable 是一个接口,里面只声明了一个方法run();返回值为void所以无法拿到执行完的结果.只能通过共享变量或者线程通信来搞定.Future就是对具体的Runable或者Callable任 ...

  2. Tyvj 1068 巧用扩展KMP

    Tyvj1068 给定两个长度为2*10^5的字符串为A和B 求B在A中匹配后,任意匹配长度的位置个数. KMP算法大家应该烂熟于心才好,这样碰到这样的题才能灵活运用.有时做题真的需要一点灵感.首先, ...

  3. JSP-Runoob:JSP 自动刷新

    ylbtech-JSP-Runoob:JSP 自动刷新 1.返回顶部 1. JSP 自动刷新 想象一下,如果要直播比赛的比分,或股票市场的实时状态,或当前的外汇配给,该怎么实现呢?显然,要实现这种实时 ...

  4. Python3基础复习

    目录 基本语法 运算符 输出格式 数据类型 数据结构 函数 面向对象 补充 异常 模块和包 文件 时间 线程和进程 基本语法 基本语法只列举与Java不一样的. 运算符 and, or而非 & ...

  5. codevs1085数字游戏(环形DP+划分DP )

    1085 数字游戏  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单, ...

  6. [Swift通天遁地]三、手势与图表-(2)监听手势事件自由拖动图像视图

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  7. 记一次MySQL索引优化

    两张表是主(CHECK_DRAWINGS)从(CHECK_DRAWINGS_IMG)关系. CHECK_DRAWINGS,主表数据 3591条. SELECT COUNT(*) FROM CHECK_ ...

  8. C#用Microsoft.Office.Interop.Word进行Word转PDF的问题

    之前用Aspose.Word进行Word转PDF发现'\'这个字符会被转换成'¥'这样的错误,没办法只能换个方法了.下面是Microsoft.Office.Interop.Word转PDF的方法: p ...

  9. CF831C Jury Marks

    思路: 关键在于“插入”一个得分之后,其他所有得分也随之确定了. 实现: #include <iostream> #include <cstdio> #include < ...

  10. 【年终糖果计划】跟风领一波糖果 candy.one 领取教程

    糖果领取网址(较为稳定):https://candy.one/i/1474564 用微信和QQ打开的朋友请复制到其他浏览器打开 糖果领取网址(较为稳定):https://candy.one/i/147 ...