首页 > 代码库 > bzoj3307 雨天的尾巴

bzoj3307 雨天的尾巴

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3307

【题解】

这什么垃圾题啊卡空间卡时间卡栈

然后我会了一种新姿势:人工栈(好像也不难啊喂)

我们发现对于每种物品,只需要在u这地方的权值线段树上+1,v的权值线段树上+1,LCA的权值线段树上-1,LCA的父亲权值线段树上-1.

算一算就会发现符合条件了。

现在需要的就是合并线段树

线段树合并是log的,然后就是O(nlogn)了

bzoj上恰好10s。。

还有一个是,本地实测,极限数据要开到1000w才能过,bzoj卡了空间我只能开600w,居然过了。。

放两个代码吧(虽然bzoj都能过?)

直接dfs,开栈命令(?)

技术分享
# pragma comment(linker, /STACK:102400000,102400000)
# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 2e5 + 10, N = 6e6 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

namespace SMT {
    int p[N], w[N], ch[N][2], siz;
    
    inline void up(int x) {
        if(w[ch[x][0]] >= w[ch[x][1]]) {
            w[x] = w[ch[x][0]];
            p[x] = p[ch[x][0]];
        } else {
            w[x] = w[ch[x][1]];
            p[x] = p[ch[x][1]];
        } 
    }
    
    inline void edt(int &x, int l, int r, int pos, int d) {
        if(!x) x = ++siz;
        if(l == r) {
            p[x] = l; 
            w[x] += d;
            return ;
        }
        int mid = l+r>>1;
        if(pos <= mid) edt(ch[x][0], l, mid, pos, d);
        else edt(ch[x][1], mid+1, r, pos, d);
        up(x); 
    }
    
    inline int merge(int x, int y, int l, int r) {
        if(!x || !y) return x+y;
        if(l == r) {
            w[x] = w[x] + w[y];
            return x;
        } 
        int mid = l+r>>1;
        ch[x][0] = merge(ch[x][0], ch[y][0], l, mid);
        ch[x][1] = merge(ch[x][1], ch[y][1], mid+1, r);
        up(x); 
        return x;
    }
}

int head[M], nxt[M], to[M], tot=0; 
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
    add(u, v), add(v, u);
}

int n, m, rt[M];
int fa[M][17], dep[M];
inline void dfs(int x, int father) {
     dep[x] = dep[father] + 1;
    fa[x][0] = father;
    for (int i=1; i<=16; ++i) fa[x][i] = fa[fa[x][i-1]][i-1];
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == father) continue;
        dfs(to[i], x);
    }
}

inline int lca(int u, int v) {
    if(dep[u] < dep[v]) swap(u, v);
    for (int i=16; ~i; --i)
        if((dep[u]-dep[v]) & (1<<i)) u = fa[u][i];
    if(u == v) return u;
    for (int i=16; ~i; --i) 
        if(fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    return fa[u][0];
}

int ans[M]; 

inline void gans(int x) {
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == fa[x][0]) continue;
        gans(to[i]); 
        rt[x] = SMT::merge(rt[x], rt[to[i]], 1, 1e9);
    }
    ans[x] = SMT::p[rt[x]]; 
}


int main() {
//    freopen("3307.in", "r", stdin);
//    freopen("3307.out", "w", stdout); 
    cin >> n >> m;
    for (int i=1, u, v; i<n; ++i) {
         scanf("%d%d", &u, &v);
        adde(u, v);
    }
    dfs(1, 0); 
    for (int i=1, u, v, z; i<=m; ++i) {
         scanf("%d%d%d", &u, &v, &z);
        int LCA = lca(u, v);
        SMT::edt(rt[u], 1, 1e9, z, 1);
        SMT::edt(rt[v], 1, 1e9, z, 1);
        SMT::edt(rt[LCA], 1, 1e9, z, -1); 
        if(LCA != 1) SMT::edt(rt[fa[LCA][0]], 1, 1e9, z, -1);
    }
    
    gans(1); 
    for (int i=1; i<=n; ++i) printf("%d\n", ans[i]); 

    return 0;
}
View Code

人工栈

技术分享
# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 2e5 + 10, N = 6e6 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

namespace SMT {
    int p[N], w[N], ch[N][2], siz;
    
    inline void up(int x) {
        if(w[ch[x][0]] >= w[ch[x][1]]) {
            w[x] = w[ch[x][0]];
            p[x] = p[ch[x][0]];
        } else {
            w[x] = w[ch[x][1]];
            p[x] = p[ch[x][1]];
        } 
    }
    
    inline void edt(int &x, int l, int r, int pos, int d) {
        if(!x) x = ++siz;
        if(l == r) {
            w[x] += d;
            if(w[x] <= 0) p[x] = 0;
            else p[x] = l; 
            return ;
        }
        int mid = l+r>>1;
        if(pos <= mid) edt(ch[x][0], l, mid, pos, d);
        else edt(ch[x][1], mid+1, r, pos, d);
        up(x); 
    }
    
    inline int merge(int x, int y, int l, int r) {
        if(!x || !y) return x+y;
        if(l == r) {
            w[x] = w[x] + w[y];
            if(w[x] <= 0) p[x] = 0;
            else p[x] = l; 
            return x;
        } 
        int mid = l+r>>1;
        ch[x][0] = merge(ch[x][0], ch[y][0], l, mid);
        ch[x][1] = merge(ch[x][1], ch[y][1], mid+1, r);
        up(x); 
        return x;
    }
    
    inline void prt(int x, int l, int r) {
        if(!x) return ; 
        printf("%d %d %d %d %d\n", x, l, r, p[x], w[x]);
        if(l == r) return;
        int mid = l+r>>1;
        prt(ch[x][0], l, mid); 
        prt(ch[x][1], mid+1, r);
    }
}

int head[M], nxt[M], to[M], tot=0; 
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
    add(u, v), add(v, u);
}

int n, m, rt[M];
int fa[M][17], dep[M];
bool vis[M]; 
queue<int> q;
inline void bfs(int x) {
    q.push(x); dep[x] = 1; 
    while(!q.empty()) {
        int top = q.front(); q.pop(); vis[top] = 1; 
        for (int i=1; i<=16; ++i) fa[top][i] = fa[fa[top][i-1]][i-1];
        for (int i=head[top]; i; i=nxt[i]) {
            if(!vis[to[i]]) {
                fa[to[i]][0] = top;
                dep[to[i]] = dep[top] + 1; 
                q.push(to[i]); 
            }
        }
    }
}

inline int lca(int u, int v) {
    if(dep[u] < dep[v]) swap(u, v);
    for (int i=16; ~i; --i)
        if((dep[u]-dep[v]) & (1<<i)) u = fa[u][i];
    if(u == v) return u;
    for (int i=16; ~i; --i) 
        if(fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    return fa[u][0];
}

int ans[M]; 
int st[M], cur[M], stn=0; 
inline void gans(int start) {
    int x, t;
    st[++stn] = start;
    while(stn) {
        x = st[stn];
        if(to[cur[x]] == fa[x][0]) cur[x] = nxt[cur[x]]; 
        if(!cur[x]) {
            --stn;
            ans[x] = SMT::p[rt[x]];
//            printf("==================%d=================\n", x);
//            SMT::prt(rt[x], 1, 1e9); 
            t = fa[x][0];
            if(t) rt[t] = SMT::merge(rt[t], rt[x], 1, 1e9);
        } else { 
            t = to[cur[x]];
            st[++stn] = t;
            cur[x] = nxt[cur[x]];
        }
    } 
}


int main() {
//    freopen("3307.in", "r", stdin);
//    freopen("3307.out", "w", stdout); 
    cin >> n >> m;
    for (int i=1, u, v; i<n; ++i) {
         scanf("%d%d", &u, &v);
        adde(u, v);
    }
    bfs(1); 
    for (int i=1, u, v, z; i<=m; ++i) {
         scanf("%d%d%d", &u, &v, &z);
        int LCA = lca(u, v);
        SMT::edt(rt[u], 1, 1e9, z, 1);
        SMT::edt(rt[v], 1, 1e9, z, 1);
        SMT::edt(rt[LCA], 1, 1e9, z, -1);  
        if(LCA != 1) SMT::edt(rt[fa[LCA][0]], 1, 1e9, z, -1);
    }
    
    for (int i=1; i<=n; ++i) cur[i] = head[i]; 
    gans(1); 
    for (int i=1; i<=n; ++i) printf("%d\n", ans[i]); 

    return 0;
}
/*
5 5
1 2
2 3
3 4
4 5
1 2 1
2 3 1
1 3 1
1 4 2
3 4 2
*/
View Code

 

bzoj3307 雨天的尾巴