多校第九场总结,树剖
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,略微增加了行數,不過,也增加了一些可讀性吧(劃掉)
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,之后用之前的結果
哪位大佬看下正確性(隊友信誓旦旦說是對的),還是數據弱
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
總結
以上是生活随笔為你收集整理的多校第九场总结,树剖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 跟我一起用node-express搭建一
- 下一篇: 【BZOJ3997】[TJOI2015]