http://bestcoder.hdu.edu.cn/blog/

02

官方题解

由于没有修改操作,一个显然的想法是离线处理所有问题
将询问拆成1-x,1-y,1-LCA(x,y),则处理的问题转化为从根到节点的链上的问题。
解决这个问题,我们可以在dfs时向treap插入当前的数,在退出时删除这个数,并且每次维护在该点上的答案。
当然也可以将所有的查询和点权排序,用树链剖分做这个题,在线段树上面插入就ok。

一开始队友说用lca让他变成,让我解决怎么求带限制的区间和的问题,
jcx说:“我负责任的告诉你,主席树”
忘了,完全忘了怎么写,出事了,于是乎,百度一波,搜到一个例题,百度那个题号
发现可以对查询排序,离线查询,分批次插入线段树(用树状数组更短更简单)

于是算法出炉:每次ask求a到b的,转化为求1到a-1和1到b,将每次ask的a-1和b同归为k,对所有的k排序去重(ks[]),每次将小于k[i]的所有礼物插入线段树,然后更新有k的ask,然后处理k[i++],实现起来巨烦无比。

然后,队友发现lca搞出的序列不清真,只能处理rmq的情况,有重复的点,算sum肯定崩盘

mdzz,czj ^-^

改算法,有重复的,树映射到线段树上,树链剖分嘛,怎么早没想到,这个时候因为写的一波离线查询的各种struct已经身心疲惫,两个队友还说,交给我,一个也不来帮忙,想砍人
树剖这里讲的不错

改完发现代码180行了,哇
为了防止自己在这一团炸裂的逻辑中迷失,这里我分了好多struct,略微增加了行数,不过,也增加了一些可读性吧(划掉)

#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3e5 + 7;
typedef long long LL;
int n;
struct gift{int pos, val;void read(int id){scanf("%d", &val);pos = id;}bool operator < (const gift & b) const {return val < b.val;}
} gifts[N];struct ZKWsegTree{#define lc (t<<1)#define rc (t<<1^1)LL sum[N];int M;inline void build(int n){M = 1; for(;M<n;)M<<=1; if(M!=1)M--;memset(sum, sizeof(sum), 0);}void add(int t, LL x){for (sum[t+=M]+=x, t>>=1; t; t>>=1){sum[t] = sum[lc] + sum[rc];}}LL query(int l, int r){LL ans = 0;for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){if (~l&1) ans += sum[l^1];if ( r&1) ans += sum[r^1];}return ans;}
} T;struct TreeChain{struct Edge{int from, to, nxt;Edge(){}Edge(int u, int v, int n):from(u), to(v), nxt(n){}}edges[N];int n, E, head[N];int tim;int siz[N]; //用来保存以x为根的子树节点个数int top[N]; //用来保存当前节点的所在链的顶端节点int son[N]; //用来保存重儿子int dep[N]; //用来保存当前节点的深度int fa[N];  //用来保存当前节点的父亲int tid[N]; //用来保存树中每个节点剖分后的新编号,线段树int Rank[N];//tid反向数组,不一定需要inline void AddEdge(int f, int t){edges[++E] = Edge(f, t, head[f]);head[f] = E;}inline void Init(int n){tim = 0;this -> n = n ; E = -1;for (int i = 0; i <= n; i++) head[i] = -1;for (int i = 0; i <= n; i++) son[i] = -1;}void dfs1(int u, int father, int d){dep[u] = d;fa[u] = father;siz[u] = 1;int nxt;for(int i = head[u]; i != -1; i = nxt){Edge &e = edges[i]; nxt = e.nxt;if (e.to == father) continue;dfs1(e.to, u, d + 1);siz[u] += siz[e.to];if(son[u]==-1 || siz[e.to] > siz[son[u]]) son[u] = e.to;}}void dfs2(int u, int tp){top[u] = tp;tid[u] = ++tim;Rank[tid[u]] = u;if (son[u] == -1) return;dfs2(son[u], tp);int nxt;for(int i = head[u]; i != -1; i = nxt){Edge &e = edges[i]; nxt = e.nxt;if(e.to == son[u] || e.to == fa[u]) continue;dfs2(e.to, e.to);}}LL query(int u, int v){int f1 = top[u], f2 = top[v];LL tmp = 0;for (; f1 != f2;){if (dep[f1] < dep[f2]){swap(f1, f2);swap(u, v);}tmp += T.query(tid[f1], tid[u]);u = fa[f1]; f1 = top[u];}if (dep[u] > dep[v]) swap(u, v);return tmp + T.query(tid[u], tid[v]);}
} g ;int ks[N], K, H;
map<int, int> hashK;
vector<int> whoAsk[N*2];
void insertK(int id, int k){if (hashK.find(k) == hashK.end()) {hashK[k] = ++H;whoAsk[H].clear();}whoAsk[hashK[k]].push_back(id);
}
struct ask{int u, v, a, b, pos;vector<LL> ans;void read(int pos){this->pos = pos;ans.clear();scanf("%d%d%d%d", &u, &v, &a, &b);a--;ks[++K] = a, ks[++K] = b;insertK(pos, a);insertK(pos, b);}
} asks[N];int main () {freopen("in.txt", "r", stdin);int m, u, v;while(cin >> n >> m) {for(int i = 1; i <= n; i++) {gifts[i].read(i);}sort(gifts + 1, gifts + n+1);g.Init(n);for(int i = 0; i < n - 1; i++) {scanf("%d%d", &u, &v);g.AddEdge(u, v);g.AddEdge(v, u);}g.dfs1(1, -1, 0);g.dfs2(1, 1);T.build(n);K = 0, H = 0;hashK.clear();for (int i = 1; i <= m; i++) asks[i].read(i);sort(ks + 1, ks + K+1);K = unique(ks + 1, ks + K+1) - (ks + 1);int cur = 1;for (int i = 1; i <= K; i++){for (int &j = cur; j  <= n; j++){if (gifts[j].val > ks[i]) break;T.add(g.tid[gifts[j].pos], gifts[j].val);}int kk = hashK[ks[i]];for (int j = 0; j < whoAsk[kk].size(); j++){ask &a = asks[whoAsk[kk][j]];a.ans.push_back(g.query(a.u, a.v));}}for (int i = 1; i <= m; i++){printf("%lld", abs(asks[i].ans[1] - asks[i].ans[0]));putchar(i==m ? '\n' : ' ');}}return 0;
}

05

官方题解说

缩点为DAG,则如果在拓扑序中出现了有两个及以上入度为0的点则不合法

哇,我咋没想到,比赛的时候看见这题刚刚开始有人A的时候都是1800ms过的,好多200msWA的

于是乎,感觉这是个大暴力,算个复杂度,好像似乎,不会炸吧(虽然后来证实极限数据会炸,6000条边)

当时的想法是,先WA一发再说,做n次dfs,然后就过了

#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N = 1e3 + 10;
const int M = 6e3 + 10;struct Dinic{struct Edge{int from, to, nxt;Edge(){}Edge(int u, int v, int n):from(u), to(v), nxt(n){}}edges[M];int n, E, head[N];bool vis[N], reach[N][N];inline void AddEdge(int f, int t){edges[++E] = Edge(f, t, head[f]);head[f] = E;}inline void Init(int n){this -> n = n ; E = -1;for (int i=0;i<=n;i++) head[i] = -1;}void dfs(int start, int u){vis[u] = 1;reach[start][u] = 1;int nxt;for (int i =  head[u]; i != -1; i = nxt){Edge &e = edges[i]; nxt = e.nxt;if (vis[e.to]) continue;dfs(start, e.to);}}inline bool live(){memset(reach, 0, sizeof(reach));for (int i = 1; i <= n; i++){memset(vis, 0, sizeof(vis));dfs(i, i);}for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){if (!(reach[i][j] | reach[j][i])) return false;}}return true;}
} g ;int main(){///freopen("in.txt", "r", stdin);int _, n, m, u, v;scanf("%d", &_);for (; _--;){scanf("%d%d", &n, &m);g.Init(n);for (; m--;){scanf("%d%d", &u, &v);g.AddEdge(u, v);}if (g.live()) puts("I love you my love and our love save us!");else puts("Light my fire!");}return 0;
}

06

官方题解

类比cf 835E,枚举二进制位按照标号当前位为1 和当前位为0分为两个集合,每次求解两个集合之间的最短路即可覆盖到所有的点对。时间复杂度20*dijstla时间

厉害厉害,我们用了一个有毒的算法,n次dj,只有第一次情况dist数组为INF,之后用之前的结果
哪位大佬看下正确性(队友信誓旦旦说是对的),还是数据弱

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<queue>
#include<vector>
using namespace std;typedef long long LL;
const int MAXN = 1e5 + 5;
typedef pair<int,int> pii;
vector<pii> vec[MAXN];
int st[MAXN];
int d[MAXN];
const int INF = 0x3f3f3f3f;
void dijkstra(int s) {priority_queue<pii, vector<pii>, greater<pii> > que;que.push(pii(0, s));while(!que.empty()) {pii p = que.top(); que.pop();int v = p.second;if(d[v] < p.first) continue;for(int i = 0; i < vec[v].size(); i++) {pii e = vec[v][i];if(e.first != s && d[e.first] > p.first + e.second) {d[e.first] = p.first + e.second;que.push(pii(d[e.first], e.first));}}}
}
int main()
{int T;cin >> T;for(int cas = 1; cas <= T; cas++) {int n, m;cin >> n >> m;for(int i = 0; i <= n; i++) vec[i].clear();for(int i = 0; i < m; i++) {int u, v, w;scanf("%d%d%d", &u, &v, &w);vec[u].push_back(pii(v, w));}int k;cin >> k;for(int i = 0; i < k; i++) {scanf("%d", st + i);}fill(d, d + n + 1, INF);for(int i = 0; i < k; i++) {dijkstra(st[i]);}int Min = INF;for(int i = 0; i < k; i++) {Min = min(Min, d[st[i]]);}printf("Case #%d: %d\n", cas, Min);}return 0;
}

08

代码这么丑,一看就不是我写的

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+10;
const int MOD = 1e9+7;
typedef long long LL;
map<int, int> mp;
vector<int> vec;
vector<int> ans;
int main () {int m;while(cin >> m) {vec.clear();ans.clear();for(int i = 0; i < m; i++) {int x;scanf("%d", &x);vec.push_back(x);mp[x]++;}//int n = (-1 + (int)sqrt(2+4*m)) / 2;sort(vec.begin(), vec.end());for(int i = 0; i < m; i++) {int x = vec[i];if(mp[x] > 0) {mp[x]--;for(int j = 0; j < ans.size(); j++) {mp[x + ans[j]]--;}ans.push_back(x);}}printf("%d\n", ans.size());for(int i = 0; i < ans.size(); i++) {printf("%d%c", ans[i], i == ans.size() - 1 ? '\n' : ' ');}}return 0;
}

10

定义dp[i][j][k],k = 0,表示A串从0~i 的子串A[0,i],能否匹配B串从0~j的子串B[0,j];k = 1,表示A[0,i] + A[i]能否匹配B[0,j]。

本来不想开这题,md开局100+提交没人过,后来没题开了

转移时考虑几种特殊情况,”a*” 可以匹配 “” ,”a”,”aa”…,”.“可以匹配”“,”a”,”b”,”aa”,”bb”…,注意 “.” 不能匹配 “ab”这种串。

现场看见很多用java交TLE的,看来是用正则表达式直接套的,本题,明明可以贪心的(划掉),队友出到数据来hack这个贪心了,丹这个时候,已经A了,果然本场数据有毒

完了,这个代码快把我丑哭了

#include<bits/stdc++.h>
using namespace std;
string a;
string b;
int cnt[100];
int main(){for(int i = 0; i < 100; i++) cnt[i] = i;int t;cin >> t;getchar();while( t-- ){getline( cin,a );getline( cin,b );bool thisflag=true;a+=']';b+=']';int positionA,positionB;positionA=positionB=cnt[2] - 2;;for( ; positionA<a.size()&&positionB<b.size(); ){if( a[positionA]==b[positionB] ){positionA++;positionB++;continue;} else if( b[positionB]=='.' ){b[positionB]=a[positionA];positionA++;positionB++;continue;} else if( b[positionB]=='*' ){if( positionB+1<b.size()&&positionB>0&&b[positionB+1]==b[positionB-1] ){swap( b[positionB],b[positionB+1] );continue;}else{while( a[positionA]==b[positionB-1] ){positionA++;}positionB++;}} else if( a[positionA]!=b[positionB] ){if( positionB+1<b.size()&&b[positionB+1]=='*' ){positionB+=2;}else{thisflag=false;break;}}}if( !thisflag ) printf( "no\n" );else printf( "yes\n" );}
}

再修一修树剖的板

不知道为什么,用char op, scanf %c会TLE
改成char op[5], scanf %s就过了
有毒

hdu3966

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 7;
typedef long long LL;
const int INF = 0x3f3f3f3f;
int n, a[N];
int tid[N]; //用来保存树中每个节点剖分后的新编号,线段树struct ZKWsegTree{int tree[N];int M, n;void build(int n){this->n = n;M = 1; while (M < n) M <<= 1; if (M!=1) M--;for (int t = 1 ; t <= n; t++) tree[tid[t]+M] = a[t];for (int t = n+1; t <= M+1; t++) tree[t+M] = INF;for (int t = M; t >= 1; t--) tree[t] = min(tree[t<<1], tree[t<<1^1]);for (int t = 2*M+1; t >= 1; t--) tree[t] = tree[t] - tree[t>>1];}void update(int l, int r, int val){int tmp;for (l+=M-1, r+=M+1; l^r^1; l>>=1, r>>=1){if (~l&1) tree[l^1] += val;if ( r&1) tree[r^1] += val;if (l > 1) tmp = min(tree[l], tree[l^1]), tree[l]-=tmp, tree[l^1]-=tmp, tree[l>>1]+=tmp;if (r > 1) tmp = min(tree[r], tree[r^1]), tree[r]-=tmp, tree[r^1]-=tmp, tree[r>>1]+=tmp;}for (; l > 1; l >>= 1){tmp = min(tree[l], tree[l^1]), tree[l]-=tmp, tree[l^1]-=tmp, tree[l>>1]+=tmp;}tree[1] += tree[0], tree[0] = 0;}int query(int t){t += M;int ans = tree[t];for (;t > 1;) ans += tree[t>>=1];return ans;}
} T;struct TreeChain{struct Edge{int from, to, nxt;Edge(){}Edge(int u, int v, int n):from(u), to(v), nxt(n){}}edges[N];int n, E, head[N];int tim;int siz[N]; //用来保存以x为根的子树节点个数int top[N]; //用来保存当前节点的所在链的顶端节点int son[N]; //用来保存重儿子int dep[N]; //用来保存当前节点的深度int fa[N];  //用来保存当前节点的父亲//int tid[N]; //用来保存树中每个节点剖分后的新编号,线段树,   全局变量了int Rank[N];//tid反向数组,不一定需要inline void AddEdge(int f, int t){edges[++E] = Edge(f, t, head[f]);head[f] = E;}inline void Init(int n){this -> n = n; E = -1; tim = 0;for (int i = 0; i <= n; i++) head[i] = -1;for (int i = 0; i <= n; i++) son[i] = -1;}void dfs1(int u, int father, int d){dep[u] = d;fa[u] = father;siz[u] = 1;int nxt;for(int i = head[u]; i != -1; i = nxt){Edge &e = edges[i]; nxt = e.nxt;if (e.to == father) continue;dfs1(e.to, u, d + 1);siz[u] += siz[e.to];if(son[u]==-1 || siz[e.to] > siz[son[u]]) son[u] = e.to;}}void dfs2(int u, int tp){top[u] = tp;tid[u] = ++tim;Rank[tid[u]] = u;if (son[u] == -1) return;dfs2(son[u], tp);int nxt;for(int i = head[u]; i != -1; i = nxt){Edge &e = edges[i]; nxt = e.nxt;if(e.to == son[u] || e.to == fa[u]) continue;dfs2(e.to, e.to);}}void update(int u, int v, int x){int f1 = top[u], f2 = top[v];for (; f1 != f2;){if (dep[f1] < dep[f2]){swap(f1, f2);swap(u, v);}T.update(tid[f1], tid[u], x);u = fa[f1]; f1 = top[u];}if (dep[u] > dep[v]) swap(u, v);T.update(tid[u], tid[v], x);}
} g ;int main () {///freopen("in.txt", "r", stdin);int n, m, q, u, v, x;char op[5];for (; ~scanf("%d%d%d", &n, &m, &q);) {for (int i = 1; i <= n; i++) scanf("%d", &a[i]);g.Init(n);for (; m--;){scanf("%d%d", &u, &v);g.AddEdge(u, v);g.AddEdge(v, u);}g.dfs1(1, 0, 0);g.dfs2(1, 1);T.build(n);for (; q--;){scanf("%s", op);if (op[0] == 'Q'){scanf("%d\n", &u);printf("%d\n", T.query(tid[u]));}else{scanf("%d%d%d\n", &u, &v, &x);if (op[0] == 'I') g.update(u, v, x);else g.update(u, v, -x);}}}return 0;
}

转载于:https://www.cnblogs.com/cww97/p/7533946.html

多校第九场总结,树剖相关推荐

  1. 2019牛客多校第九场AThe power of Fibonacci(广义BM)

    2019牛客多校第九场AThe power of Fibonacci(广义BM) 题目大意 求斐波那契数列m次方的前n项和 解题思路 显然,斐波那契的m次方前缀和依然是线性递推,因此考虑用exBM求解 ...

  2. 2018 Multi-University Training Contest 9 杭电多校第九场 (有坑待补)

    咕咕咕了太久  多校博客直接从第三场跳到了第九场orz 见谅见谅(会补的!) 明明最后看下来是dp场 但是硬生生被我们做成了组合数专场-- 听说jls把我们用组合数做的题都用dp来了遍 这里只放了用组 ...

  3. Cutting Bamboos(牛客多校第九场H主席树+二分+思维)

    链接:https://ac.nowcoder.com/acm/contest/889/H 来源:牛客网 There are n bamboos arranged in a line. The i-th ...

  4. 牛客多校第九场 H Cutting Bamboos —— 主席树

    题目链接:点我啊╭(╯^╰)╮ 题目大意: 给你一片竹林,编号 1 1 1 到 n n n ,给定初始高度     每次查询区间,问一共砍 y y y 刀的时候,第 x x x 刀的高度     要求 ...

  5. 2019多校第九场 HDU6681 Rikka with Cake(欧拉图论定理,线段树)

    链接:HDU6681 Rikka with Cake 题意: 给出一个笛卡尔坐标系中左下角坐标为(0,0)(0,0)(0,0),右上角坐标为(n,m)(n,m)(n,m)的矩形,有K  (≤105)K ...

  6. 2019牛客多校第九场 H Cutting Bamboos (二分主席树)

    看到题解说二分 心里也有数了..... H Cutting Bamboos 给了一些高度得柱子 每区间你可以坎y次 y次之后 必须砍没有了 没有砍 总长度得一样 问第x次砍得高度在哪里 因为砍得次数 ...

  7. Quadratic equation(二次剩余)2019牛客多校第九场

    链接:https://ac.nowcoder.com/acm/contest/889/B 来源:牛客网 题目描述 Amy asks Mr. B problem B. Please help Mr. B ...

  8. 数学--数论--HDU6919 Senior PanⅡ【2017多校第九场】

    Description 给出一个区间[L,R][L,R],问该区间中所有以KK作为最小因子(大于11的)的数字之和 Input 第一行输入一整数TT表示用例组数,每组用例输入三个整数L,R,KL,R, ...

  9. 2021HDU多校第九场1008HDU7073 Integers Have Friends 2. 随机化

    HUD地址:https://acm.hdu.edu.cn/showproblem.php?pid=7073  题目大意:选择数组中最多的数,使得他们模m同余(m>=2).求最大的数量. 思路:然 ...

最新文章

  1. 企业微信发送企业红包java_发放企业红包
  2. 【分布式事务】tcc-transaction分布式TCC型事务框架搭建与实战案例(基于Dubbo/Dubbox)...
  3. 2021-07-29 labelme注释、分类和Json文件转化(转化成彩图mask)
  4. 设计模式-组合+策略模式
  5. 【browser】chinese chrome shows as english
  6. kafka学习_Kafka学习笔记下
  7. WebView性能优化--独立进程
  8. PyMC3和Lasagne构建神经网络(ANN)和卷积神经网络(CNN)
  9. CentOS6 安装Sendmail + Dovecot + Squirrelmail
  10. SQL Server修改标识列方法 如自增列的批量化修改
  11. ERROR: CMake must be installed to build dlib
  12. JaveScript简单数据类型(JS知识点归纳二)
  13. ++递归 字符串全排列_Ann全排列的枚举_递归实现(基于Python)
  14. 2020线性代数辅导讲义练习答案
  15. ps怎么加底部阴影_ps影子(ps物体底部阴影怎么做)
  16. 雅虎邮箱为什么停止服务_雅虎的发展项目将变成什么样?
  17. 英语中学生测试软件,初中生免费学英语的软件哪个好
  18. SSM | Spring
  19. 华为 AI 芯片诞生;马云重当中国首富;微软修复数据删除 Bug | 极客头条
  20. 华为云照片的爬虫程序更新(python3.6)

热门文章

  1. linux useradd(adduser)命令参数及用法详解(linux创建新用户命令)
  2. 地图篇-01.获取用户位置
  3. Oracle面试过程中常见的二十个问题
  4. stm32无法进入串口接收中断
  5. API接口通讯参数规范
  6. react使用 PropTypes 和 getDefaultProps()
  7. [计算机视觉][神经网络与深度学习]Faster R-CNN配置及其训练教程
  8. ZOJ 38727(贪心)
  9. ASP.NET中常用到的27个函数集
  10. swoole 使用 xdebug 实现调试模式(PHPSTORM)