[jzoj]3875.【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)

Link

  https://jzoj.net/senior/#main/show/3875

Problem

  在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。
  但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。
  为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

Solution

  题目太长也太烦,幼稚而又没智商。

  题目大意是:“给你n个点,m条边,给出p个询问,每个询问给出一条边,先连这条边,然后判断两个点是否处在环内,是的话就输出环的大小”

  我们考虑使用一种方便计算答案的连边方式

  对于输入的m+p条边,我们每次连的边,要符合以下条件才连

  连了这条边,不会让图中有环。

  为什么这样连是对的呢?因为连了对答案没有任何贡献。

  怎么判环呢?用并查集判断两点祖先是否相同,并给祖先之间连一条边。

  根据这个判定条件连完边,整个图,就是一个森林(很多树)。

  在之后的判断里,如果这条边在有判定条件的那次连边中连过了,那说明他怎么连都不会构成环,所以输出No。

  然后,再对之前没有连的边处理。我们设当前没有连的边为x~y

  那么,连了这个边一定会构成一个环,这个环的大小,其实就是求x~lca(x,y)+y~lca(x,y)的长度,可以看下面的图。(红色代表边x~y,其中,黑色圈圈住的部分即环的大小)

   

  找出了答案后,我们进行缩点处理。

  因为这环中每一个点的答案,都是一样的,所以,我们可以把答案存在lca这个点上,在之后的询问中,如果遇到这个环中的点,就跳到lca的地方去。这个操作,同样用并查集操作。把环中的点,他们的father,直接赋值为lca。但是,不是将他们的祖先赋值为lca的祖先上去。

  每次我们找到一个点,我们直接跳到他f数组中的父亲上,以免重复计算同一个环上的数值。

  如果一个在执行操作时,一个环中套一个环,那么先形成的环,他的父亲通过并查集,一定赋值为后形成的环的父亲,故只计算一次。

  大概流程:每次模拟找lca,然后跳到当前点并查集中的父亲上,知道跳到他们的lca,计算答案。

Code

  打得很臭,也很丑,见谅

{$inline on}
var
        n,m,p,i,j,x,y,xx,yy,tot,ans,lca:longint;
        bz:array[0..400000] of boolean;
        a:array[0..400000,0..2] of longint;
        l,pre,d:array[0..800000] of longint;
        f,re,dad,dis,shen,have:array[0..200000] of longint;
procedure insert(x,y:longint); inline;
begin
        inc(tot);
        d[tot]:=y;
        pre[tot]:=l[x];
        l[x]:=tot;
end;

function getfather(x:longint):longint; inline;
begin
        if f[x]=0 then exit(x);
        f[x]:=getfather(f[x]);
        exit(f[x]);
end;

procedure he(x,y:longint);   inline;
var
        fx,fy:longint;
begin
        fx:=getfather(x);
        fy:=getfather(y);

        if fx<>fy then
                f[fx]:=fy;

end;

procedure build(x,num,q:longint); inline;
var
        k:longint;
begin
        dad[x]:=q;
        shen[x]:=num;

        k:=l[x];
        while k<>0 do
        begin
                if dis[d[k]]=0 then
                begin
                        dis[d[k]]:=1;

                        build(d[k],num+1,x);
                end;

                k:=pre[k];
        end;
end;

procedure check(var x,y:longint);   inline;
begin
        while shen[x]<>shen[y] do
        begin
                while shen[x]>shen[y] do
                begin
                        ans:=ans+re[x];

                        inc(have[0]);
                        have[have[0]]:=x;

                        x:=dad[x];

                        x:=getfather(x);
                end;

                while shen[x]<shen[y] do
                begin
                        ans:=ans+re[y];

                        inc(have[0]);
                        have[have[0]]:=y;

                        y:=dad[y];

                        y:=getfather(y);
                end;
        end;
end;

begin
        readln(n,m,p);

        for i:=1 to m+p do
        begin
                readln(x,y);

                if getfather(x)<>getfather(y) then
                begin
                        he(x,y);

                        insert(x,y);
                        insert(y,x);

                        bz[i]:=true;
                end;

                a[i,1]:=x;
                a[i,2]:=y;
        end;

        for i:=1 to n do
                if dis[i]=0 then
                begin
                        dis[i]:=1;

                        build(i,1,i);
                end;

        fillchar(f,sizeof(f),0);

        for i:=1 to n do
                re[i]:=1;

        for i:=1 to m do
        begin
                if bz[i] then
                        continue;

                x:=getfather(a[i,1]);
                y:=getfather(a[i,2]);

                ans:=0;
                have[0]:=0;

                check(x,y);

                while x<>y do
                begin
                        ans:=ans+re[x]+re[y];

                        inc(have[0]);
                        have[have[0]]:=x;
                        inc(have[0]);
                        have[have[0]]:=y;

                        x:=dad[x];
                        y:=dad[y];

                        x:=getfather(x);
                        y:=getfather(y);

                        check(x,y);
                end;

                ans:=ans+re[x];

                re[x]:=ans;

                for j:=1 to have[0] do
                begin
                        f[have[j]]:=x;

                        re[have[j]]:=ans;
                end;
        end;
        /////////////////////////////////////////////////////////////

        for i:=m+1 to m+p do
        begin
                if bz[i] then
                begin
                        writeln(‘No‘);

                        continue;
                end;

                x:=getfather(a[i,1]);
                y:=getfather(a[i,2]);

                ans:=0;
                have[0]:=0;

                check(x,y);

                while x<>y do
                begin
                        ans:=ans+re[x]+re[y];

                        inc(have[0]);
                        have[have[0]]:=x;
                        inc(have[0]);
                        have[have[0]]:=y;

                        x:=dad[x];
                        y:=dad[y];

                        x:=getfather(x);
                        y:=getfather(y);

                        check(x,y);
                end;

                ans:=ans+re[x];

                re[x]:=ans;

                writeln(ans);

                for j:=1 to have[0] do
                begin
                        f[have[j]]:=x;

                        re[have[j]]:=ans;
                end;
        end;
end.
时间: 2024-10-06 07:20:42

[jzoj]3875.【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)的相关文章

八校联考第一场(20170917)

排列(permutation)题目描述]给定一个n*n 的矩阵f,你需要求出有多少个1~n 的排列x 满足对于1<=i≠j<=n,均有f[i,j]=min(x[i],x[j]),并输出字典序最小的一个.有多组数据.[输入数据]第一行一个整数t 表示数据组数.每组数据第一行一个正整数n.接下来n 行每行n 个整数,第i行第j 列的整数表示f[i,j].[输出数据]对于每组数据,如果不存在这样的排列,输出一行一个整数-1.否则输出两行,第一行一个整数表示排列个数对998244353 取模的结果,第

八校联考第二场(二试)(20170924)

NOIP 信心赛zzq题目名称函数排列数字串代码文件名func perm num输入文件名func.in perm.in num.in输出文件名func.out perm.out num.out时间限制1s 2s 2s空间限制512MB 512MB 512MB子任务分值10 20 30 40 10 20 20 10 40 20 30 30 20题目类型传统传统传统比较方式全文比较(忽略行末空格和文末换行)全文比较(忽略行末空格和文末换行)全文比较(忽略行末空格和文末换行)1. 题目难度和顺序大致

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的

【BZOJ5251】【八省联考2018】劈配(网络流,二分答案)

[BZOJ5251][八省联考2018]劈配(网络流,二分答案) 题面 洛谷 BZOJ Description 一年一度的综艺节目<中国新代码>又开始了. Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayid顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的: 总共n名参赛选手(编号从1至n)每人写出一份代码并介绍自己的梦想.接着由所有导师对这些选手进行排名. 为了避免后续的麻烦,规定不存在排名并列的情况. 同

九校联考 终&amp;启

one term's ending... class:12 school:130...130...130... 至今没有看到九校的排名,如果九校排名正常的话,那yyhs的学生也太可怕了...估计要三百开外了 语文是比较意外的分数,尽管选择题做得差,可是有史以来第一次下110....why 数学和英语都比预估的低. 政史地84 65 78,感觉最对不起历史老师...地理从来没好过. 物化技82 75 83,是时候改课了..... 明明下半学期一直在学文化课...现在连浙大线都考不上了.... 学考

[jzoj]3456.【NOIP2013模拟联考3】恭介的法则(rule)

Link https://jzoj.net/senior/#main/show/3456 Description 终于,在众亲们的奋斗下,最终boss 恭介被关进了库特设计的密室.正当她们松了一口气时,这个世界却发生了天翻覆地的变化:地面开始下沉,天空开始变成血红色,海水沸腾……一幅世界末日的图景.美鱼从她手中的古籍<若山牧水诗歌集>中发现了原因:白鸟は かなしからずや 空の青 海のあをにも 染まずただよふ .大(xia)意(shuo)就是狡猾的恭介在创造这个世界的时候就篡改了法则.而这个法则

多校联考九场总结

总算考完了九套试题,天天早上坐五个小时,下午都会头痛的要死QAQ 不过考的貌似不错? 九场平均分 215.78 数一数考场上没有1A的题目吧(不算有毒的OJ卡我常数): 1.超立方体 QAQ 当时并不会FWT,矩阵乘法搞出系数来之后只能暴力贡献 然后输入的时候没有直接取模爆了long long,于是暴力也被炸飞了 后来学了FWT发现是水题 2.IP地址 没有使用合适的转化询问的方式 使得这道题目可以用打标记的方式来做 转化的一些经典方式:差分,叶节点查询转化为链求和,区间可减性查询转化为前缀查询

[八省联考2018] 劈配

题目背景 一年一度的综艺节目<中国新代码>又开始了.Zayid 从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayid 顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的: 总共n 名参赛选手(编号从1 至n)每人写出一份代码并介绍自己的梦想.接着 由所有导师对这些选手进行排名.为了避免后续的麻烦,规定不存在排名并列的情况. 同时,每名选手都将独立地填写一份志愿表,来对总共 m 位导师(编号从 1 至 m)作出评价.志愿表

20181009noip HZ EZ两校联考sum(莫队,组合数学)

题面戳这里 思路: noip考莫队???!!! 考场上死活没往这方面想啊!!!数据分治忘写endl50pts滚粗了 这里每个询问都有n,m两个参数 我们可以把它看做常规莫队中的l和r 然后利用组合数的可递推性质就好了 相信改变m大家都会写,n呢? 看图: 我们发现,$S_n^m = S_{n-1}^m \times 2 - C_n^{m+1} + C_{n-1}^{m+1}$ (因为杨辉三角的性质) 所以n也可以递推 套个莫队就好了 代码: #include<iostream> #includ