codeforces gym 101142G Gangsters in Central City

7 篇文章 0 订阅
6 篇文章 0 订阅

简略题意:一棵树,每个节点有一个局面,根是水源,边是水管。初始每个居民都有水喝。
操作有两种:
‘+ v’, v处的居民楼被强盗占领。
‘- v’, v处的强盗走了。
对于每个询问,你需要切断一些水管,使得所有强盗没水喝,没水喝的居民尽量少。

因为必须有边切才行,所以需要切除的边数最多就是与原来的根相连的边的数目。
原来的树拆成了若干个子树,每个子树的根也有一个边可以切除。

单独考虑每个子树的问题,对于这个子树内的所有强盗,只要切除根到这些强盗的lca处的任意一条边即可,不过我们需要最小化被影响的居民数,因此我们切除这些边中深度最大的lca上的边。

现在的唯一难点就是若干个点的lca怎么求,若干个点的共同lca就是这些点中dfs序的最小值和最大值点的lca.
我们可以对每个树根维护一个set,用来取这个树内的强盗点的最大dfs序和最小dfs序。
每次来一个强盗,我们找到对应的树根,插入这个点的dfs序。
每次走一个强盗,我们找到对应的树根,擦除这个点的dfs序。
然后更新答案即可。
复杂度 O(qlogn+nlogn) .

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;

namespace solver {
    const int maxn = 150000;
    int n, m;
    vector<int> G[maxn];
    int deep[maxn], p[maxn][20], cnt[maxn], belong[maxn], sum[maxn], cut[maxn];
    int L[maxn], R[maxn], id = 0;
    set<int> st[maxn];
    void Dfs(int u, int fa, int root) {
        cnt[u] = 0;
        bool isok = 1;
        p[u][0] = fa;
        if(root != 0)
            belong[u] = root;
        for(auto v:G[u]) {
            if(v == fa) continue;
            deep[v] = deep[u] + 1;
            if(u == 1) Dfs(v, u, v);
            else Dfs(v, u, root);
            cnt[u] += cnt[v];
            isok = 0;
        }
        if(isok) cnt[u] = 1, L[u] = ++id, R[id] = u;
    }
    int lca_up(int u, int len) {
        for(int i = 19; i >= 0; i--) {
            if(u != -1 && (len & (1<<i))) {
                u = p[u][i];
            }
        }
        return u;
    }
    int lca(int u, int v) {
        if(deep[u] < deep[v]) swap(u, v);
        int d = deep[u] - deep[v];
        u = lca_up(u, d);
        if(u == v) return u;
        for(int i = 19; i >= 0; i--) {
            if(p[u][i] == p[v][i]) continue;
            u = p[u][i];
            v = p[v][i];
        }
        return p[u][0];
    }
    void solve() {
        scanf("%d%d", &n, &m);
        for(int i = 2; i <= n; i++) {
            int u = i, v;
            scanf("%d", &v);
            G[v].push_back(u);
            G[u].push_back(v);
        }
        deep[1] = 0;
        Dfs(1, -1, -1);
        for(int i = 1; i < 20; i++) {
            for(int j = 1; j <= n; j++) {
                if(p[j][i-1] == -1) p[j][i] = -1;
                else p[j][i] = p[p[j][i-1]][i-1];
            }
        }
        int ans1 = 0, ans2 = 0;
        for(int i = 1; i <= m; i++) {
            char c;
            int d;
            scanf(" %c %d", &c, &d);
            int f = belong[d];
            if(c == '+') {
                if(sum[f] == 0) {
                    ans1++;
                    sum[f]++;
                    st[f].insert(L[d]);
                    cut[f] = d;
                } else {
                    int pc = cut[f];
                    int pv = cnt[pc] - sum[f];

                    sum[f]++;
                    st[f].insert(L[d]);
                    int ll = *st[f].begin(), rr = *st[f].rbegin();
                    ll = R[ll], rr = R[rr];
                    int nc = lca(ll, rr);
                    int nv = cnt[nc] - sum[f];
                    cut[f] = nc;
                    ans2 += nv - pv;
//                    cout<<nc<<" "<<cnt[nc]<<" sss "<<pv<<" "<<nv<<" "<<pc<<endl;
                }
            } else {
                if(sum[f] == 1) {
                    ans1--;
                    sum[f]--;
                    st[f].erase(L[d]);
                    cut[f] = 0;
                } else {
                    int pc = cut[f];
                    int pv = cnt[pc] - sum[f];

                    sum[f]--;
                    st[f].erase(L[d]);
                    int ll = *st[f].begin(), rr = *st[f].rbegin();
                    ll = R[ll], rr = R[rr];
                    int nc = lca(ll, rr);
                    int nv = cnt[nc] - sum[f];
                    cut[f] = nc;
                    ans2 += nv - pv;
                }
            }
            cout<<ans1<<" "<<ans2<<endl;
        }
    }
}

int main() {
    #ifdef file
    freopen("gangsters.in", "r", stdin);
    freopen("gangsters.out", "w", stdout);
    #endif // file
    solver::solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。GymCodeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值