【BZOJ2322】[BeiJing2011]梦想封印

Description

渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解。

为了分析一种奇特的称为梦想封印(Fantasy Seal)的特技,需要引入如下的概念:

每一位魔法的使用者都有一个“魔法脉络”,它决定了可以使用的魔法的种类。

一般地,一个“魔法脉络”可以看作一个无向图,有N个结点及M条边,将结点编号为1~N,其中有一个结点是特殊的,称为核心(Kernel),记作1号结点。每一条边有一个固有(即生成之后再也不会发生变化的)权值,是一个不超过U的自然数。

每一次魔法驱动,可看作是由核心(Kernel)出发的一条有限长的道路(Walk),可以经过一条边多次,所驱动的魔法类型由以下方式给出:

将经过的每一条边的权值异或(xor)起来,得到s。

如果s是0,则驱动失败,否则将驱动编号为s的魔法(每一个正整数编号对应了唯一一个魔法)。

需要注意的是,如果经过了一条边多次,则每一次都要计入s中。

这样,魔法脉络决定了可使用魔法的类型,当然,由于魔法与其编号之间的关系尚未得到很好的认知,此时人们仅仅关注可使用魔法的种类数。

梦想封印可以看作是对“魔法脉络”的破坏:

该特技作用的结果是,“魔法脉络”中的一些边逐次地消失。

我们记总共消失了Q条边,按顺序依次为Dis1、Dis2、……、DisQ。

给定了以上信息,你要计算的是梦想封印作用过程中的效果,这可以用Q+1个自然数来描述:

Ans0为初始时可以使用魔法的数量。

Ans1为Dis1被破坏(即边被删去)后可以使用魔法的数量。

Ans2为Dis1及Dis2均被破坏后可使用魔法的数量。

……

AnsQ为Dis1、Dis2、……、DisQ全部被破坏后可以使用魔法的数量。

Input

第一行包含三个正整数N、M、Q。

接下来的M行,每行包含3个整数,Ai、Bi、Wi,表示一条权为Wi的与结点Ai、Bi关联的无向边,其中Wi是不超过U的自然数。

接下来Q行,每行一个整数:Disi。

Output

一共包Q+1行,依次为Ans0、Ans1、……、AnsQ。

Sample Input

【输入样例1】
3 3 2
1 2 1
2 3 2
3 1 4
1
3
【输入样例2】
5 7 7
1 2 1
1 3 1
2 4 2
2 5 2
4 5 4
5 3 9
4 3 1
7
6
5
4
3
2
1

Sample Output

【输出样例1】
5
2
0
【样例1解释】
初始时可使用编号为1、3、4、6、7的魔法。
在删去第1条边(连结1、2结点的边)后,可使用4和6号魔法。
第3条边(连结第1、3结点的边)也被删去后,核心(Kernel)即结点1孤立,易知此时无法使用魔法。
【输出样例2】
15
11
5
2
2
1
1
0

HINT

【数据规模和约定】
所有数据保证该无向图不含重边、自环。

所有数据保证不会有一条边被删除多次,即对于不同i和j,有Disi≠Disj

30%的数据中N ≤ 50,M ≤ 50,Q ≤50,U≤100;

60%的数据中N ≤ 300,M ≤ 300,Q ≤50,U≤10^9;

80%的数据中N ≤ 300,M ≤ 5000,Q ≤5000,U≤10^18;

100%的数据中N ≤ 5000,M ≤ 20000,Q ≤20000,U≤10^18;

题解:又一道神题

我们回忆2155那道题的做法:所有从1到一个点的路径的异或和 都可以表示成 任意一条从1到该节点的路径 和 某些简单环 的异或和。

那么本题变成了动态求异或和的种类数,我们首先的思路就是将删边变成倒着往图中加边。然后思考一下我们具体都需要维护些什么。

从答案的角度分析,答案=(所有本质不同的路径数)*2^(本质不同的环的个数)-1,注意本质不同的路径包括哪里都不走,所以最后要-1。具体本质不同是什么意思呢?

回忆2155那道题,本质不同的环的意思就是:将所有环高斯消元后得到的线性基,因为这样就可以表示任意环的异或和。

那么本质不同的路径的意思也就出来了,我们最终得到的不简单的路径的异或和=任意一条简单路径的异或和^任意一些环的异或和,所以两条简单路径本质不同当且仅当它们用线性基消元后,得到的值不同。具体地,我们可以用set来维护这样的路径。

好了,分析了这么多,现在我们终于可以得出一个可行的做法了:当加入边(a,b)时:

1.若a,b都已经被访问过(或者说加入的是一条非树边),我们此时得到了一个简单环,将这个简单环的异或和放到线性基中消元,如果没有消成0,那就说明我们应该将这个圆加入到线性基中去,直接把它加入到线性基中对应的位置就行了。但是注意一点,更改线性基后,之前的路径并没有被这条边消元,所以要把set里的边一个一个取出来,重新消元再塞回去。

2.若a被访问过b没有被访问过(或者说加入了一条树边),我们应该DFSb所在的连通块。在DFS的过程中,每搜到一个点,我们就计算出从1到这个点的路径的异或和,消元后看一下跟以前的是否重复,如果不重复就扔到set里。此外,每搜到一条树边,我们就继续向下搜索;每搜到一条非树边,我们就又得到了一个简单环,按照1中的处理方法去处理就行了。

3.若a,b都没有被访问过(我们也不知道它将会是树边还是非树边),不用管就好。

感觉实现要比理论简单一些。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <algorithm>
typedef long long ll;
using namespace std;
int n,m,cnt,q;
int to[40010],next[40010],head[10010],pa[40010],pb[40010],del[40010],tag[40010],vis[10010];
ll val[40010],dis[10010],pc[40010],ans[40010];
ll v[110];
set<ll> s;
set<ll>::iterator it;
bool cmp(ll a,ll b)
{
return a>b;
}
ll query(ll x)
{
for(int j=1;j<=v[0];j++) if((x^v[j])<x) x^=v[j];
return x;
}
void updata(ll x)
{
if(!x) return ;
ll tmp;
for(it=s.begin();it!=s.end();it=s.upper_bound(tmp))
{
tmp=*it;
if((tmp^x)<tmp) s.erase(it),s.insert(tmp^x);
}
v[++v[0]]=x;
for(int j=v[0];j>=2;j--)
{
if(v[j]>v[j-1]) swap(v[j],v[j-1]);
else break;
}
}
void add(int a,int b,ll c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x,int fa)
{
vis[x]=1;
ll tmp=query(dis[x]);
if(tmp&&s.find(tmp)==s.end()) s.insert(tmp);
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa) continue;
if(!vis[to[i]]) dis[to[i]]=dis[x]^val[i],dfs(to[i],x);
else updata(query(dis[x]^dis[to[i]]^val[i]));
}
}
void insert(int a,int b,ll c)
{
add(a,b,c),add(b,a,c);
if(vis[a]&&vis[b])
{
updata(query(dis[a]^dis[b]^c));
return ;
}
if(!vis[a]&&!vis[b]) return ;
if(vis[b]) swap(a,b);
dis[b]=dis[a]^c,dfs(b,a);
}
int main()
{
memset(head,-1,sizeof(head));
vis[1]=1;
scanf("%d%d%d",&n,&m,&q);
int i;
for(i=1;i<=m;i++) scanf("%d%d%lld",&pa[i],&pb[i],&pc[i]);
for(i=1;i<=q;i++) scanf("%d",&del[i]),tag[del[i]]=1;
for(i=1;i<=m;i++) if(!tag[i]) insert(pa[i],pb[i],pc[i]);
s.insert(0);
ans[q+1]=(s.size()*1ll<<v[0])-1;
for(i=q;i>=1;i--)
{
insert(pa[del[i]],pb[del[i]],pc[del[i]]);
ans[i]=(s.size()*(1ll<<v[0]))-1;
}
for(i=1;i<=q+1;i++) printf("%lld\n",ans[i]);
return 0;
}

【BZOJ2322】[BeiJing2011]梦想封印 高斯消元求线性基+DFS+set的更多相关文章

  1. 【BZOJ2460】[BeiJing2011]元素 贪心+高斯消元求线性基

    [BZOJ2460][BeiJing2011]元素 Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法 ...

  2. 【BZOJ2115】[Wc2011] Xor 高斯消元求线性基+DFS

    [BZOJ2115][Wc2011] Xor Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ...

  3. 【bzoj2115】[Wc2011] Xor DFS树+高斯消元求线性基

    题目描述 输入 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图 ...

  4. 【bzoj3105】[cqoi2013]新Nim游戏 高斯消元求线性基

    题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从 ...

  5. 【bzoj4004】[JLOI2015]装备购买 贪心+高斯消元求线性基

    题目描述 脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量zi(aj ,.....,am) 表示 (1 <= i <= n; 1 <= j < ...

  6. 【bzoj4269】再见Xor 高斯消元求线性基

    题目描述 给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值. 输入 第一行一个正整数N. 接下来一行N个非负整数. 输出 一行,包含两 ...

  7. HDU3949/AcWing210 XOR (高斯消元求线性基)

    求第k小的异或和,用高斯消元求更简单一些. 1 //用高斯消元求线性基 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define ...

  8. 【BZOJ2844】albus就是要第一个出场 高斯消元求线性基

    [BZOJ2844]albus就是要第一个出场 Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2 ...

  9. BZOJ 4269 高斯消元求线性基

    思路: 最大: 所有线性基异或一下 次大: 最大的异或一下最小的线性基 搞定~ //By SiriusRen #include <cstdio> #include <algorith ...

随机推荐

  1. hibernate.cfg.xml配置文件对关联关系的书写技巧!

    以Department(部门类)和User(用户类)作为例子: 类图如下: 一般hibernate.cfg.xml的配置文件开头都是如下: <?xml version="1.0&quo ...

  2. Hive 脚本执行

    hive执行脚本 hive -e “sql语句” 会将查询的结果打印在控制台上.  hive -e “sql语句” >> xxx 会将查询的结果重定向到xxx文件中,会显示OK和抓取的数据 ...

  3. 【HTML 元素】嵌入图像

    img元素允许我们在HTML文档里嵌入图像. 要嵌入一张图像需要使用src和alt属性,代码如下: <img src="../img/example/img-map.jpg" ...

  4. eclipse黄色警告(finally block does not complete normally) ,不建议在finally中使用return语句

    在eclipse中编写例如以下的代码,eclipse会给出黄色告警:finally block does not complete normally. public class Test { publ ...

  5. [转]php-fpm配置具体解释

    [转]php-fpm配置具体解释 php-fpm具体解释 原文链接:http://php-fpm.anight.org/wiki:http://www.php-fpm.com/翻译:http://sy ...

  6. iOS使用自己定义字体

    1.加入相应的字体(.ttf或.odf)到project的resurce,比如my.ttf. 2.在info.plist中加入一项 Fonts provided by application (ite ...

  7. 【Excle数据透视表】如何在数据透视表顶部显示列总计数据

    解决方案 创建组并修改组名称为“合计” 如下图:原始数据透视表 步骤 选中列标签区域→右键→组合 修改组合的名称为“合计” 此时底部会有一个合计汇总项,只需要单击数据透视表任意单元格→数据透视表工具→ ...

  8. JavaScript 获取文件名,后缀名

    function getBaseName(str) { var segs = str.split('.'); if(segs.length > 1) segs.pop(); return seg ...

  9. MySQL - Show Processlist 整理(转)

      原文来源:MySQL 5.5 Reference Manual 部分翻译取自:<MySQL_5.1中文参考手册> 转载请注明原文链接http://www.cnblogs.com/len ...

  10. Convolutional Patch Networks with Spatial Prior for Road Detection and Urban Scene Understanding

    Convolutional Patch Networks with Spatial Prior for Road Detection and Urban Scene Understanding 深度学 ...