清明夢超能力者黃YY[樹鏈剖分+掃描線,線段樹合併]

清明夢超能力者黃YY

題目連接

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

暫時有兩種做法.

算法一

涉及:樹鏈剖分,掃描線

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

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

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

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

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

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

算法二

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

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

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

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

算法一.代碼

#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);
    else
        change(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);
    else
        return 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);
    else
        insert(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]];
        else
            u = 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);
    else
        return 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章