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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

清明梦超能力者黄YY[树链剖分+扫描线,线段树合并]

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 清明梦超能力者黄YY[树链剖分+扫描线,线段树合并] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

清明夢超能力者黃YY

題目連接

https://www.nowcoder.com/acm/contest/206/I

暫時有兩種做法.

算法一

涉及:樹鏈剖分,掃描線

在一個線段的情況下,我們可以把一個染色區間拆成左端點處增加事件,右端點處刪除事件.
維護一顆權值線段樹.
這樣,端點從小到大掃描時,遇到增加事件就在線段樹指定位置+1,遇到刪除事件就在線段樹指定位置-1.

那么要回答一個點的答案只需要掃到這個點的時候,在權值線段樹里二分kkk大值即可.

這個搬到了樹上,我們照樣可以使用掃描線的方法來做.

對于每一個染色區間,將其剖到樹鏈上去,可以剖出最多log(n)log(n)log(n)個小區間.

這些小區間的深度較小的端點加入增加事件,深度較大的端點加入刪除事件.

然后對整棵樹按照dfndfndfn序列從小到大依次掃描即可,注意掃描的過程中也要維護一顆權值線段樹.

算法二

涉及:dfs,權值線段樹合并

對于每個詢問u,vu,vu,v,應該在uuu處加入增加事件,在vvv處加入增加事件,在lca(u,v)lca(u,v)lca(u,v)處加入刪除事件,在faz[lca(u,v)]faz[lca(u,v)]faz[lca(u,v)]處加入刪除事件.因此每個詢問會產生444個事件.

我們采用dfs的順序,每個點維護一顆權值線段樹,然后后序遍歷到達一個節點時候,先將它所有兒子的線段樹進行合并,合并完成后,將該點涉及到的增加或刪除事件執行到線段樹上,此時,該點的權值線段樹維護的就是橫跨這個節點的所有染色區間.

然后在權值線段樹上進行kkk大詢問即可得到該點的答案.

算法一.代碼

#include <iostream> #include <algorithm> #include <cstring> #include <vector> #define pr(x) std::cout << #x << ':' << x << std::endl #define rep(i,a,b) for(int i = a;i <= b;++i) #define clr(x) memset(x,0,sizeof(x))const int N = 100007;struct edge{int v,nxt; }es[N<<1];int head[N],tot;void addedge(int u,int v){es[tot].v = v;es[tot].nxt = head[u];head[u] = tot++; }int faz[N],siz[N],dep[N],top[N],son[N],dfn[N],rnk[N],idx;void dfs1(int u,int fa,int deep) {faz[u] = fa;siz[u] = 1;dep[u] = deep;for(int e = head[u];e != -1;e = es[e].nxt) {int v = es[e].v;if(v == fa) continue;dfs1(v,u,deep+1);siz[u] += siz[v];if(!son[u] || siz[v] > siz[son[u]])son[u] = v;} }void dfs2(int u,int tp) {dfn[u] = ++idx;rnk[idx] = u;top[u] = tp;if(son[u]) dfs2(son[u],tp);for(int e = head[u];e != -1;e = es[e].nxt) {int v = es[e].v;if(son[u] != v && faz[u] != v)dfs2(v,v);} }struct node{int val,len;node(int val = 0,int len = 1):val(val),len(len){} }ns[N<<2];node maintain(node &lch,node &rch) {return node(lch.val + rch.val,lch.len + rch.len); }void change(int o,int l,int r,int pos,int val) {if(l == r) {ns[o].val += val;return ;}int mid = (l + r) >> 1;if(pos <= mid)change(o<<1,l,mid,pos,val);elsechange(o<<1|1,mid+1,r,pos,val);ns[o] = maintain(ns[o<<1],ns[o<<1|1]); }int kth(int o,int l,int r,int x) {if(ns[o].val < x) return 0;if(l == r) return l; int mid = (l + r) >> 1;if(x > ns[o<<1].val)return kth(o<<1|1,mid+1,r,x-ns[o<<1].val);elsereturn kth(o<<1,l,mid,x); }struct event{int tp,val;event(int tp = 0,int val = 0):tp(tp),val(val){} };std::vector<event> events[N];int color[N];void modify(int x,int y,int id) {while(top[x] != top[y]) {if(dep[top[x]] < dep[top[y]])std::swap(x,y);events[dfn[x]].push_back(event(-1,id));events[dfn[top[x]]].push_back(event(1,id));x = faz[top[x]];}if(dep[x] < dep[y])std::swap(x,y);events[dfn[x]].push_back(event(-1,id));events[dfn[y]].push_back(event(1,id)); }int n,m,k; int ans[N]; int main() {memset(head,-1,sizeof(head));std::ios::sync_with_stdio(false);std::cin >> n >> m >> k;rep(i,1,n-1) {int x,y;std::cin >> x >> y;addedge(x,y);addedge(y,x);}dfs1(1,-1,0);dfs2(1,1);rep(i,1,m){int u,v,c;std::cin >> u >> v >> c;color[m+1-i] = c;modify(u,v,m+1-i);}rep(i,1,n) {for(auto e : events[i]){if(e.tp == 1)change(1,1,n,e.val,1);}ans[rnk[i]] = color[kth(1,1,n,k)];for(auto e : events[i]) {if(e.tp == -1)change(1,1,n,e.val,-1);}}rep(i,1,n) {std::cout << ans[i] << " ";}return 0; }

算法二.代碼

#include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <assert.h> #define pr(x) std::cout << #x << ':' << x << std::endl #define rep(i,a,b) for(int i = a;i <= b;++i) #define clr(x) memset(x,0,sizeof(x)) #define setinf(x) memset(x,0x3f,sizeof(x))const int N = 100007; std::vector<int> edge[N];struct node {int sum,lch,rch;node(int sum = 0,int lch = 0,int rch = 0):sum(sum),lch(lch),rch(rch){} }ns[N*60]; int tot;node maintain(node &lch,node &rch,int l,int r) {return node(lch.sum+rch.sum,l,r); }void insert(int& o,int l,int r,int pos,int add) {if(!o)o = ++tot;if(l == r) {ns[o].sum += add;return ;}int mid = (l + r) >> 1;if(pos <= mid)insert(ns[o].lch,l,mid,pos,add);elseinsert(ns[o].rch,mid+1,r,pos,add);ns[o] = maintain(ns[ns[o].lch],ns[ns[o].rch],ns[o].lch,ns[o].rch); }node query(int o,int l,int r,int ql,int qr) {if(o == 0) return ns[0];if(ql <= l && r <= qr)return ns[o];if(r < ql || qr < l)return ns[0];int mid = (l + r) >> 1;node lch = query(ns[o].lch,l,mid,ql,qr);node rch = query(ns[o].rch,mid+1,r,ql,qr);return maintain(lch,rch,0,0); }int merge(int a,int b) {if(!a) return b;if(!b) return a;int o = ++tot;assert(o < N*60);ns[o].sum = ns[a].sum + ns[b].sum;ns[o].lch = merge(ns[a].lch,ns[b].lch);ns[o].rch = merge(ns[a].rch,ns[b].rch);return o; }int ans[N],color[N];int faz[N],siz[N],top[N],dep[N],dfn[N],son[N],idx;void dfs1(int u,int fa,int deep) {faz[u] = fa;dep[u] = deep;siz[u] = 1;for(auto v : edge[u]) {if(v == fa) continue;dfs1(v,u,deep+1);siz[u] += siz[v];if(siz[son[u]] < siz[v])son[u] = v;} }void dfs2(int u,int tp) {dfn[u] = ++idx;top[u] = tp;if(son[u])dfs2(son[u],tp);for(auto v : edge[u]) {if(v == faz[u] || v == son[u]) continue;dfs2(v,v);} }int lca(int u,int v) {while(top[u] != top[v]) {if(dep[top[u]] < dep[top[v]])v = faz[top[v]];elseu = faz[top[u]];}return dep[u] > dep[v] ? v : u; }int kth(int o,int l,int r,int k) {if(!o || ns[o].sum < k)return 0;if(l == r) return l;int mid = (l + r) >> 1;if(k <= ns[ns[o].lch].sum)return kth(ns[o].lch,l,mid,k);elsereturn kth(ns[o].rch,mid+1,r,k-ns[ns[o].lch].sum); }int n,m,k; int root[N]; std::vector<int> add[N],dec[N]; void dfs(int u,int fa) {for(auto v : edge[u]) {if(v == fa) continue;dfs(v,u);root[u] = merge(root[u],root[v]);}for(auto x : dec[u]){insert(root[u],1,n,x,-1);}for(auto y : add[u]){insert(root[u],1,n,y,1);}ans[u] = color[kth(root[u],1,n,k)]; }int main() {std::ios::sync_with_stdio(false);std::cin >> n >> m >> k;rep(i,1,n-1) {int u,v;std::cin >> u >> v;edge[u].push_back(v);edge[v].push_back(u);}dfs1(1,0,0);dfs2(1,1);for(int i = m;i >= 1;--i) {int u,v;std::cin >> u >> v >> color[i];add[u].push_back(i);add[v].push_back(i);int _lca = lca(u,v);dec[_lca].push_back(i);dec[faz[_lca]].push_back(i);}dfs(1,0);rep(i,1,n) {std::cout << ans[i] << " ";}std::cout << std::endl;return 0; }

總結

以上是生活随笔為你收集整理的清明梦超能力者黄YY[树链剖分+扫描线,线段树合并]的全部內容,希望文章能夠幫你解決所遇到的問題。

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