Bzoj1969: [Ahoi2005]LANE 航线规划

题面

戳我

Sol

把询问反过来,变成加边,先加上边变成一棵树,之后每次加边就相当于去掉这两个点与这条边形成的环的代价,用树剖+线段树覆盖区间即可

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e5 + 10);

IL ll Read(){
    RG ll x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, fst[_], nxt[_], to[_], cnt, m, Q, ans[_], use[_];
int dfn[_], Index, fa[_], size[_], top[_], son[_], deep[_];
int sum[_ << 1], cov[_ << 1];
struct Qry{
    int c, u, v, id;
    IL bool operator <(RG Qry A) const{
        if(c != A.c) return c < A.c;
        return u != A.u ? u < A.u : v < A.v;
    }
} qry[_];
struct Edge{
    int u, v, flg;
    IL bool operator <(RG Edge A) const{  return u != A.u ? u < A.u : v < A.v;  }
} edge[_];

IL void Add(RG int u, RG int v){  to[cnt] = v; nxt[cnt] = fst[u]; fst[u] = cnt++;  }

IL int Find(RG int x){  return x == fa[x] ? x : fa[x] = Find(fa[x]);  }

IL void Dfs1(RG int u, RG int ff){
    size[u] = 1; fa[u] = ff; deep[u] = deep[ff] + 1;
    for(RG int e = fst[u]; e != -1; e = nxt[e]){
        if(to[e] == ff) continue;
        Dfs1(to[e], u);
        size[u] += size[to[e]];
        if(size[to[e]] > size[son[u]]) son[u] = to[e];
    }
}

IL void Dfs2(RG int u, RG int Top){
    top[u] = Top; dfn[u] = ++Index;
    if(son[u]) Dfs2(son[u], Top);
    for(RG int e = fst[u]; e != -1; e = nxt[e]) if(!dfn[to[e]]) Dfs2(to[e], to[e]);
}

IL void Build(RG int x, RG int l, RG int r){
    sum[x] = r - l + 1;
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    Build(x << 1, l, mid); Build(x << 1 | 1, mid + 1, r);
}

IL void Pushdown(RG int x){
    if(!cov[x]) return;
    cov[x << 1] = cov[x << 1 | 1] = 1;
    cov[x] = sum[x << 1] = sum[x << 1 | 1] = 0;
}

IL void Modify(RG int x, RG int l, RG int r, RG int L, RG int R){
    if(L <= l && R >= r){  sum[x] = 0; cov[x] = 1; return;  }
    RG int mid = (l + r) >> 1;
    Pushdown(x);
    if(L <= mid) Modify(x << 1, l, mid, L, R);
    if(R > mid) Modify(x << 1 | 1, mid + 1, r, L, R);
    sum[x] = sum[x << 1] + sum[x << 1 | 1];
}

IL int Query(RG int x, RG int l, RG int r, RG int L, RG int R){
    if(L <= l && R >= r) return sum[x];
    RG int mid = (l + r) >> 1, ans = 0;
    Pushdown(x);
    if(L <= mid) ans = Query(x << 1, l, mid, L, R);
    if(R > mid) ans += Query(x << 1 | 1, mid + 1, r, L, R);
    sum[x] = sum[x << 1] + sum[x << 1 | 1];
    return ans;
}

IL void Cover(RG int u, RG int v){
    while(top[u] ^ top[v]){
        if(deep[top[u]] < deep[top[v]]) swap(u, v);
        Modify(1, 1, n, dfn[top[u]], dfn[u]);
        u = fa[top[u]];
    }
    if(deep[u] > deep[v]) swap(u, v);
    if(u != v) Modify(1, 1, n, dfn[u] + 1, dfn[v]);
}

IL int Calc(RG int u, RG int v){
    RG int ret = 0;
    while(top[u] ^ top[v]){
        if(deep[top[u]] < deep[top[v]]) swap(u, v);
        ret += Query(1, 1, n, dfn[top[u]], dfn[u]);
        u = fa[top[u]];
    }
    if(deep[u] > deep[v]) swap(u, v);
    if(u != v) ret += Query(1, 1, n, dfn[u] + 1, dfn[v]);
	return ret;
}

IL bool Cmp(RG Qry A, RG Qry B){  return A.id > B.id;  }

int main(RG int argc, RG char* argv[]){
    n = Read(); m = Read();
    for(RG int i = 1; i <= n; ++i) fa[i] = i, fst[i] = -1;
    for(RG int i = 1; i <= m; ++i){
        edge[i].u = Read(), edge[i].v = Read();
        if(edge[i].u > edge[i].v) swap(edge[i].u, edge[i].v);
    }
    for(RG int c = Read(); c != -1; c = Read()){
        ans[++Q] = -1; qry[Q].u = Read(); qry[Q].v = Read(); qry[Q].c = c; qry[Q].id = Q;
        if(qry[Q].u > qry[Q].v) swap(qry[Q].u, qry[Q].v);
    }
    sort(edge + 1, edge + m + 1); sort(qry + 1, qry + Q + 1);
    RG int g = Q;
    for(RG int i = 1; i <= Q; ++i) if(qry[i].c){  g = i; break;  }
    for(RG int l = 1, r = 1; l <= m && r <= g; ++l){
        while((qry[r].u < edge[l].u || (qry[r].u == edge[l].u && qry[r].v < edge[l].v)) && r <= g) ++r;
        if(qry[r].u == edge[l].u && qry[r].v == edge[l].v) edge[l].flg = 1;
    }
    sort(qry + 1, qry + Q + 1, Cmp);
    for(RG int i = 1; i <= m; ++i){
        if(edge[i].flg) continue;
        RG int fx = Find(edge[i].u), fy = Find(edge[i].v);
        if(fx == fy) continue;
        fa[fx] = fy; use[i] = 1;
        Add(edge[i].u, edge[i].v); Add(edge[i].v, edge[i].u);
    }
    Dfs1(1, 0); Dfs2(1, 1); Build(1, 1, n);
    for(RG int i = 1; i <= m; ++i) if(!edge[i].flg && !use[i]) Cover(edge[i].u, edge[i].v);
    for(RG int i = 1; i <= Q; ++i)
        if(qry[i].c == 0) Cover(qry[i].u, qry[i].v);
        else ans[qry[i].id] = Calc(qry[i].u, qry[i].v);
    for(RG int i = 1; i <= Q; ++i) if(ans[i] != -1) printf("%d\n", ans[i]);
    return 0;
}

posted @ 2018-01-15 08:11  Cyhlnj  阅读(162)  评论(0编辑  收藏  举报