【题解】 NC5205E 水灾

水灾

https://ac.nowcoder.com/acm/contest/5205/E

solution

首先可以发现,这张图其实可以转化为一棵最大生成树。

我们按权值从大到小加入边,如果新加入的边所连接的两点,已经可以通过其他权值更大的边相连,后面的询问中只删除这条边起不到任何作用。

所以我们考虑建出 重构树

具体建立方法:对于在生成树中的一条边,新建一个节点,并且从所在的集合分别连边。将的点权设为的边权。并将所在的集合改为。最终重构树的根节点为最后新建的节点。

重构树中,每个生成树中的节点在重构树中全都是叶子节点。生成树中两个节点之间的路径最小值为重构树中这两个点的点权。

利用这条性质,我们考虑回答询问。对于每个询问,我们如果暴力处理,可以删除这个点任意两个点路径上的最小权值,也就是在重构树上这两个点的。最后答案就是这些中权值最大值。

因为重构树上一个节点的权值小于它子树的权值。所以我们想要深度比较大的那些就行了。(感性理解一下吧,我也不知道该咋说了qwq)。所以按照dfs序排个序。然后每次查询相邻的两个点的即可。

下面来说为什么直接建立生成树是错的!

先给出一组hack数据(并不一定能hack到所有这种程序,因为排序结果和具体建数方式有关)

7 6 1
1 2 5
1 5 5
2 3 5
2 4 1
5 6 5
5 7 5
3 3 4 6

也就是下面这张图。

我们要求不能连通,按照序排序后就是的顺序。路径上的最小边是路径上的最小边是。这样我们两次计算删掉的都是这条边,而此时仍是可以互达的。然后就了。

code

/*
* @Author: wxyww
* @Date:   2020-04-24 21:17:32
* @Last Modified time: 2020-04-25 19:51:50
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 1000010,logN = 20;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1; c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0'; c = getchar();
    }
    return x * f;
}
struct node {
    int u,v,w;
}a[N];
bool cmp(const node &A,const node &B) {
    return A.w > B.w;
}

vector<int>e[N];

int S[N],w[N],id[N],fa[N];
int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void uni(int x,int y,int k) {
    x = x,y = y;
    if(rand() & 1) swap(x,y);
    fa[x] = y;

    S[y] = k;
}
int tot,cnt;
int dep[N],lca[N][logN + 2];
void dfs(int u) {
    id[u] = ++cnt;

    for(int i = 1;i <= logN; ++i) {
        lca[u][i] = lca[lca[u][i - 1]][i - 1];
    }

    for(vector<int>::iterator it = e[u].begin();it != e[u].end();++it) {
        lca[*it][0] = u;
        dep[*it] = dep[u] + 1;
        dfs(*it);
    }
}

int LCA(int x,int y) {
    if(dep[x] < dep[y]) swap(x,y);
    for(int i = logN;i >= 0;--i) {
        if(dep[lca[x][i]] >= dep[y]) {
            x = lca[x][i];
        }
    }
    for(int i = logN;i >= 0;--i) {
        if(lca[x][i] != lca[y][i])
            x = lca[x][i],y = lca[y][i];
    }
    if(x != y) x = lca[x][0];
    return x;
}
int tmp[N];
bool cmp2(int x,int y) {
    return id[x] < id[y];
}
int main() {
    int n = read(),m = read(),Q = read();
    for(int i = 1;i <= m;++i) {
        int u = read(),v = read(),w = read();
        a[i].u = u;a[i].v = v;a[i].w = w;
    }

    sort(a + 1,a + m + 1,cmp);
    for(int i = 1;i <= n;++i) fa[i] = i,S[i] = i;
    tot = n;
    for(int i = 1;i <= m;++i) {
        int u = a[i].u,v = a[i].v;
        u = find(u),v = find(v);
        if(u != v) {
            ++tot;
            // printf("%d %d\n%d %d\n",tot,S[u],tot,S[v]);
            e[tot].push_back(S[u]);
            e[tot].push_back(S[v]);
            w[tot] = a[i].w;
            uni(u,v,tot);
        }
    }

    dfs(tot);
    int lst = 0;
    while(Q--) {
        int k = read();
        for(int i = 1;i <= k;++i) tmp[i] = read() ^ lst;
        sort(tmp + 1,tmp + k + 1,cmp2);
        lst = 0;
        for(int i = 2;i <= k;++i) {
            printf("%d %d\n",tmp[i - 1],tmp[i]);
            lst = max(lst,w[LCA(tmp[i - 1],tmp[i])]);
        }
        printf("%d\n",lst);
    }
    return 0;
}

/*

7 6 1
1 2 5
1 5 5
2 3 5
2 4 1
5 6 5
5 7 5
3 3 4 6
*/
全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务