【LOJ】 #2013. 「SCOI2016」幸运数字
题解
最大异或和,明显是个线性基
然而还有那么多路径……那就树分治,反正点数看起来很少,就是为了让人乘上一个60的常数嘛
把一个树的点分树记录下来,然后看看询问的两个点彼此相同的最后一个父亲是谁,把这个询问挂在这个点上,计算就暴力搜索这棵树里每一个节点到重心的线性基就行了,最后再用60的常数把两个线性基合起来
代码
#include <bits/stdc++.h>
//#define ivorysi
#define MAXN 20005
#define MAXQ 200005
typedef long long int64;
typedef unsigned int u32;
using namespace std;
struct node {
int to,next;
}edge[MAXN * 2];
int head[MAXN],sumE,n,m;
int64 val[MAXN];
vector<int> aux[MAXN],qry[MAXN];
bool vis[MAXN];
int que[MAXN],qr,ql;
int siz[MAXN],son[MAXN],fa[MAXN];
int st[MAXQ],ed[MAXQ];
int64 dp[MAXN][65],ans[MAXQ];
void add(int u,int v) {
edge[++sumE].to = v;
edge[sumE].next = head[u];
head[u] = sumE;
}
void addtwo(int u,int v) {
add(u,v);add(v,u);
}
int calc_G(int u) {
que[ql = qr = 1] = u;
fa[u] = 0;
while(ql <= qr) {
int now = que[ql++];
siz[now] = 1;son[now] = 0;
for(int i = head[now] ; i ; i = edge[i].next) {
int v = edge[i].to;
if(!vis[v] && fa[now] != v) {
que[++qr] = v;
fa[v] = now;
}
}
}
int res = que[qr];
for(int i = qr ; i >= 1 ; --i) {
int now = que[i];
siz[fa[now]] += siz[now];
if(siz[now] > son[fa[now]]) son[fa[now]] = siz[now];
if(qr - siz[now] > son[now]) son[now] = qr - siz[now];
if(son[now] < son[res]) res = now;
}
return res;
}
void dfs(int u) {
int G = calc_G(u);
vis[G] = 1;
for(int i = 1 ; i <= qr ; ++i) aux[que[i]].push_back(G);
for(int i = head[G] ; i ; i = edge[i].next) {
int v = edge[i].to;
if(!vis[v]) dfs(v);
}
}
void Init() {
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= n ; ++i) scanf("%lld",&val[i]);
int u,v;
for(int i = 1 ; i < n ; ++i) {
scanf("%d%d",&u,&v);
addtwo(u,v);
}
dfs(1);
for(int i = 1 ; i <= m ; ++i) {
scanf("%d%d",&st[i],&ed[i]);
if(st[i] == ed[i]) ans[i] = val[st[i]];
}
for(int i = 1 ; i <= m ; ++i) {
if(st[i] == ed[i]) continue;
int s = min(aux[st[i]].size(),aux[ed[i]].size());
bool flag = false;
for(int j = 0 ; j < s ; ++j) {
if(aux[st[i]][j] != aux[ed[i]][j]) {
qry[aux[st[i]][j - 1]].push_back(i);
flag = 1;
break;
}
}
if(!flag) qry[aux[st[i]][s - 1]].push_back(i);
}
}
void insert(int id,int64 v) {
for(int j = 60 ; j >= 0 ; --j) {
if(v >> j & 1) {
if(dp[id][j]) v ^= dp[id][j];
else {
dp[id][j] = v;
for(int k = 60 ; k > j ; --k) {
if(dp[id][k] >> j & 1) dp[id][k] ^= dp[id][j];
}
break;
}
}
}
}
void calc(int u) {
que[ql = qr = 1] = u;
fa[u] = 0;
memset(dp[u],0,sizeof(dp[u]));
while(ql <= qr) {
int now = que[ql++];
for(int i = head[now] ; i ; i = edge[i].next) {
int v = edge[i].to;
if(!vis[v] && fa[now] != v) {
fa[v] = now;
memcpy(dp[v],dp[now],sizeof(dp[now]));
insert(v,val[v]);
que[++qr] = v;
}
}
}
}
void Process(int u) {
for(auto k : aux[u]) vis[u] = 1;
calc(u);
for(auto k : qry[u]) {
memset(dp[n + 1],0,sizeof(dp[n + 1]));
insert(n + 1,val[u]);
for(int i = 0 ; i <= 60 ; ++i) {
if(dp[st[k]][i]) insert(n + 1,dp[st[k]][i]);
if(dp[ed[k]][i]) insert(n + 1,dp[ed[k]][i]);
}
for(int i = 60 ; i >= 0 ; --i) {
if(!dp[n + 1][i]) continue;
if(!(ans[k] >> i & 1)) ans[k] ^= dp[n + 1][i];
}
}
for(auto k : aux[u]) vis[u] = 0;
}
void Solve() {
memset(vis,0,sizeof(vis));
for(int i = 1 ; i <= n ; ++i) {
if(qry[i].size() != 0) {
Process(i);
}
}
for(int i = 1 ; i <= m ; ++i) {
printf("%lld\n",ans[i]);
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}
【LOJ】 #2013. 「SCOI2016」幸运数字的更多相关文章
- loj#2013. 「SCOI2016」幸运数字 点分治/线性基
题目链接 loj#2013. 「SCOI2016」幸运数字 题解 和树上路径有管...点分治吧 把询问挂到点上 求出重心后,求出重心到每个点路径上的数的线性基 对于重心为lca的合并寻味,否则标记下传 ...
- loj #2013. 「SCOI2016」幸运数字
#2013. 「SCOI2016」幸运数字 题目描述 A 国共有 n nn 座城市,这些城市由 n−1 n - 1n−1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以 ...
- LOJ #2013「SCOI2016」幸运数字
时限为什么这么大啊 明摆着放多$ log$的做法过啊$QAQ$ LOJ #2013 题意 有$ Q$次询问,每次询问树上一条链,点有点权,你需要选择一些链上的点使得异或和尽量大 点数$ \leq 2* ...
- AC日记——「SCOI2016」幸运数字 LiBreOJ 2013
「SCOI2016」幸运数字 思路: 线性基: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 20005 # ...
- 「洛谷3292」「BZOJ4568」「SCOI2016」幸运数字【倍增LCA+线性基+合并】
[bzoj数据下载地址]不要谢我 先讲一下窝是怎么错的... \(MLE\)是因为数组开小了.. 看到异或和最大,那么就会想到用线性基. 如果不会线性基的可以参考一下我的学习笔记:「线性基」学习笔记a ...
- loj2013 「SCOI2016」幸运数字
点分治+线性基 (为了这六个字窝调了一下午一晚上QAQ #include <iostream> #include <cstring> #include <cstdio&g ...
- loj#2015. 「SCOI2016」妖怪 凸函数/三分
题目链接 loj#2015. 「SCOI2016」妖怪 题解 对于每一项展开 的到\(atk+\frac{dnf}{b}a + dnf + \frac{atk}{a} b\) 令$T = \frac{ ...
- loj#2016. 「SCOI2016」美味
题目链接 loj#2016. 「SCOI2016」美味 题解 对于不带x的怎么做....可持久化trie树 对于带x,和trie树一样贪心 对于答案的二进制位,从高往低位贪心, 二进制可以表示所有的数 ...
- loj#2012. 「SCOI2016」背单词
题目链接 loj#2012. 「SCOI2016」背单词 题解 题面描述有点不清楚. 考虑贪心 type1的花费一定不会是优的,不考虑, 所以先把后缀填进去,对于反串建trie树, 先填父亲再填儿子, ...
随机推荐
- Codeforces Round #407 (Div. 2)A B C 水 暴力 最大子序列和
A. Anastasia and pebbles time limit per test 1 second memory limit per test 256 megabytes input stan ...
- XML签名Cannot resolve element with ID XXXX 解决方案
最近同银行做接口联调,需要对XML文件做加签和解签操作,本地的开发环境是Mac 10.10,JDK的版本是1.6.0.65.小小的一段加签代码,一直报错,却久久也找不到解决方法,网上的资料非常少,错误 ...
- [吴恩达机器学习笔记]12支持向量机4核函数和标记点kernels and landmark
12.支持向量机 觉得有用的话,欢迎一起讨论相互学习~Follow Me 12.4 核函数与标记点- Kernels and landmarks 问题引入 如果你有以下的训练集,然后想去拟合其能够分开 ...
- 持久化的基于L2正则化和平均滑动模型的MNIST手写数字识别模型
持久化的基于L2正则化和平均滑动模型的MNIST手写数字识别模型 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献Tensorflow实战Google深度学习框架 实验平台: Tens ...
- JAVA Thread Dumps 三部曲
一.windows环境下方法 1:cmd下找到运行服务器容器的PID jps -v 例: C:\Users\Administrator>jps -v4856 Bootstrap -Djdk.tl ...
- BZOJ 2083 vector的巧用+二分
2083: [Poi2010]Intelligence test Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 469 Solved: 227[Su ...
- 重构改善既有代码设计--重构手法19:Replace Data Value with Object (以对象取代数据值)
你有一笔数据项(data item),需要额外的数据和行为. 将这笔数据项变成一个对象. class Order... private string customer; ==> class Or ...
- SpringCloud(二)注册服务提供者搭建
上文已经写了如何去搭建注册中心,仅有注册中心是远远不够的,所以我们需要注册到注册中心并提供服务的节点,这里称为注册服务提供者 前提 阅读上文,并成功搭建注册中心,环境无需改变 项目搭建 这里我们需要新 ...
- MySQL性能优化之道
1.in和not in子查询优化 not in 是不能命中索引的,所以以下子查询性能很低. 如果是确定且有限的集合时,可以使用.如 IN (0,1,2). 用 exists或 notexists代替 ...
- windos下创建软链接,附Linux下创建软链接
用过好多次老是忘记: 写在这里忘了就来看下 Windows下(win7) mklink /D D:\phpStudy\WWW\yii\school\teacher\web\uploads\public ...