还需要加强分析题目特殊性质,设计对应特殊算法,少想多写大力dfs剪枝不要管MLETLE直接上的能力

红包是一个有艺术细胞的男孩子。

红包由于NOI惨挂心情不好,暑假作业又多,于是他开始在作业本上涂鸦。

一开始,他在纸上画了一棵 nn 个节点的树。但是他觉得这样的画太简单了,体现不出他高超的绘画功底,于是他又额外画上了 kk 条边。

然而他觉得这样画面太复杂,于是想删去一些边使得这个无向图仍然是连通的。

请帮红包求出删边的方案数。两个方案被认为是不同的当且仅当存在一条边在其中一组中被删而另一组中没有。(什么边都不删也算一种方案)

输入格式

第一行两个整数,n,kn,k。保证 1≤n≤105,k≥01≤n≤105,k≥0。

接下来 n−1n−1 行,描述了红包最开始画的那颗树。每行两个整数 v,uv,u 表示 vv 和 uu 之间有一条无向边。

接下来 kk 行,描述了红包后来加的边。每行两个整数 v,uv,u 表示红包在 vv 和 uu 之间又加上了一条边。数据保证树中原有的边不会被再添加一次且 v≠uv≠u。

保证 1≤v,u≤n1≤v,u≤n。

输出格式

一个整数,表示方案数。你只用输出答案对 998244353998244353(7×17×223+17×17×223+1,一个质数)取模后的值。


题目分析

关于离线维护动态图连通性有一种常见套路:处理出原图的一颗dfs树,再为每一条非树边随机分配一个权值,剩下的树边权值就是所有经过它的非树边权值异或和。那么选出的边集对原图连通性没有影响当且仅当该边集的权值两两线性无关。

之前做过一题的套路就是这样的:【思维题 集合hash 树上差分】11.5撸树

关于这个随机化算法的证明,网上找到两篇高质量的证明 “图不连通 iff 删掉边集的权值线性相关”,

  1. 杜教的Dzy loves Chinese证明
  2. bzoj3569 DZY Loves Chinese II 正确性证明

对于这题,首先注意到k不大,那么就不需要常规做法的双哈希pair,而是直接将第i条非树边权值设为$2^{i-1}$.这样一来就能够在保证正确性的前提下减少常数。第二,如何求一个集合的线性无关子集个数?注意到这里的线性无关子集大小与集合元素种类都是和k同阶的。然后就可以用 算法七 的暴力dfs寻找线性无关子集数量,而因为“线性无关”这道剪枝“十分有力”,所以uoj榜上这个做法吊打标算……

 #include<bits/stdc++.h>
#define MO 998244353
typedef unsigned long long ull;
const int maxn = ;
const int maxm = ; struct Edge
{
int v,id;
Edge(int a=, int b=):v(a),id(b) {}
}edges[maxm];
struct node
{
ull val,cnt;
}a[maxm];
struct LinearBasis
{
ull a[];
bool insert(ull x)
{
for (int i=,chk=; i>=&&!chk; i--)
if ((x>>i)&){
if (a[i]) x ^= a[i];
else a[i] = x, chk = true;
}
return x > ;
}
};
int n,k,m,cnt,u[],v[];
int edgeTot,head[maxn],nxt[maxm];
ull eval[maxm],enod[maxn];
long long ans; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void addedge(int u, int v, int id)
{
edges[++edgeTot] = Edge(v, id), nxt[edgeTot] = head[u], head[u] = edgeTot;
edges[++edgeTot] = Edge(u, id), nxt[edgeTot] = head[v], head[v] = edgeTot;
}
void color(int x, int fa)
{
for (int i=head[x]; i!=-; i=nxt[i])
{
int v = edges[i].v, id = edges[i].id;
if (v==fa) continue;
color(v, x), enod[x] = enod[x]^enod[v], eval[id] = enod[v];
}
}
void dfs(int x, LinearBasis s, int c)
{
if (x==cnt+) ans = (ans+c)%MO;
else{
dfs(x+, s, c);
if (s.insert(a[x].val))
dfs(x+, s, 1ll*c*a[x].cnt%MO);
}
}
int main()
{
memset(head, -, sizeof head);
n = read(), k = read();
for (int i=; i<n; i++)
addedge(read(), read(), i);
for (int i=; i<=k; i++)
u[i] = read(), v[i] = read(), eval[i+n-] = (ull)1ll<<i,
enod[u[i]] = enod[u[i]]^eval[i+n-], enod[v[i]] = enod[v[i]]^eval[i+n-];
color(, );
m = n+k-;
std::sort(eval+, eval+m+);
for (int i=,j=; i<=m; i=j)
if (eval[i]){
for (j=i; eval[j]==eval[i]&&j<=m; j++);
a[++cnt].val = eval[i], a[cnt].cnt = j-i;
}else ++j;
dfs(, LinearBasis(), );
printf("%lld\n",ans);
return ;
}

END

【线性基 集合hash】uoj#138. 【UER #3】开学前的涂鸦的更多相关文章

  1. UOJ #138. 【UER #3】开学前的涂鸦

    Description 红包是一个有艺术细胞的男孩子. 红包由于NOI惨挂心情不好,暑假作业又多,于是他开始在作业本上涂鸦. 一开始,他在纸上画了一棵 n 个节点的树.但是他觉得这样的画太简单了,体现 ...

  2. bzoj4568: [Scoi2016]幸运数字(LCA+线性基)

    4568: [Scoi2016]幸运数字 题目:传送门 题解: 好题!!! 之前就看过,当时说是要用线性基...就没学 填坑填坑: %%%线性基 && 神犇 主要还是对于线性基的运用和 ...

  3. [CQOI2013]新Nim游戏(博弈论,线性基)

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

  4. HDU - 3949 :XOR(线性基,所有集合的不同异或和中,求从小到大第K个)

    XOR is a kind of bit operator, we define that as follow: for two binary base number A and B, let C=A ...

  5. uoj#36. 【清华集训2014】玛里苟斯(线性基+概率期望)

    传送门 为啥在我看来完全不知道为什么的在大佬们看来全都是显然-- 考虑\(k=1\)的情况,如果序列中有某一个\(a_j\)的第\(i\)位为\(1\),那么\(x\)的第\(i\)位为\(1\)的概 ...

  6. UOJ #36 -【清华集训2014】玛里苟斯(线性基+暴搜)

    UOJ 题面传送门 看到 \(k\) 次方的期望可以很自然地想到利用低次方和维护高次方和的套路进行处理,不过.由于这里的 \(k\) 达到 \(5\),直接这么处理一来繁琐,二来会爆 long lon ...

  7. UOJ#36. 【清华集训2014】玛里苟斯 线性基

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ36.html 题解 按照 $k$ 分类讨论: k=1 : 我们考虑每一位的贡献.若有至少一个数第 $i$ ...

  8. BZOJ.3811.玛里苟斯(线性基)

    BZOJ UOJ 感觉网上大部分题解对我这种数学基础差的人来说十分不友好...(虽然理解后也觉得没有那么难) 结合两篇写的比较好的详细写一写.如果有错要指出啊QAQ https://blog.csdn ...

  9. Xor && 线性基练习

    #include <cstdio> #include <cstring> ; ; int cnt,Ans,b,x,n; inline int Max(int x,int y) ...

随机推荐

  1. ContOS7分区并挂载硬盘(gpt)

    parted fdisk [只支持MSDOS分区布局] parted [支持MSDOS.GPT分区布局] 分区有三个步骤: 第一个步骤就是用分区工具进行分区 第二个步骤就是创建文件系统(也就是格式化) ...

  2. 学霸笔记系列 - Python Selenium项目实战(一)—— 怎么去验证一个按钮是启用的(可点击)?

    Q: 使用 Python Selenium WebDriver 怎么去验证一个按钮是启用的(可点击)? A:Selenium WebDriver API 里面给出了解决方法is_enabled() 使 ...

  3. spring retry注解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  4. python_魔法方法(五):描述符和定制序列

    描述符(property的原理) 描述符(descripto),用一句话来解释,描述符就是某种特殊的类的实例指派给另一个类的属性.那么什么是特殊类型的类呢?就是至少要在这个类中定义__get__(). ...

  5. 032 Longest Valid Parentheses 最长有效括号

    给一个只包含 '(' 和 ')' 的字符串,找出最长的有效(正确关闭)括号子串的长度.对于 "(()",最长有效括号子串为 "()" ,它的长度是 2.另一个例 ...

  6. E. Beautiful Subarrays 字典树

    http://codeforces.com/contest/665/problem/E 给定一个序列,问其中有多少个区间,所有数字异或起来 >= k 看到异或,就应该想到异或的性质,A^B^B ...

  7. Spark Mllib里的分层抽样(使用map作为分层抽样的数据标记)

    不多说,直接上干货! 具体,见 Spark Mllib机器学习实战的第4章 Mllib基本数据类型和Mllib数理统计

  8. Spring注解之@Lazy注解,源码分析和总结

    一 关于延迟加载的问题,有次和大神讨论他会不会直接或间接影响其他类.spring的好处就是文档都在代码里,网上百度大多是无用功. 不如,直接看源码.所以把当时源码分析的思路丢上来一波. 二 源码分析 ...

  9. Unity C# 反射

    什么是反射 在.NET中的反射也可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是个什么东西,另外.NET中的反射还可以运态创建出对象并执行它其中的方法. 反 ...

  10. AD Framework 发布(一)

      1.     EF Code First 发布时,需要配置数据库账号,账号需要存在服务器角色中具备 diskadmin,public,sysadmin 权限. 2.    数据库不存在时,会通过数 ...