日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多校第九场总结,树剖

發布時間:2025/6/17 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多校第九场总结,树剖 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

總結

以上是生活随笔為你收集整理的多校第九场总结,树剖的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。