題目大意見原題面。
其實這個題的思路非常簡單,我們知道一些數字的最大異或和可以用線性基來在o(l
ogva
lmax
)o(log\ val_)
o(lo**
alma
x)時間內快速求取,而線性基的合併也才o(l
og2v
alma
x)
o(log^2\ val_)
o(log2
valm
ax)
,所以我們可以用個資料結構維護線性基,然後每次查詢就將那條鏈上的線性基拿出來求取答案即可。
用線段樹+樹鏈剖分來,雖然支援修改,但這個方法不好寫,而且複雜度還多乙個log
nlogn
logn
。由於沒有修改所以直接預處理倍增陣列和倍增的線性基,然後每次跳一遍合併出線性基即可。
第二種方法只有o((
n+q)
logn
(602
))
o((n+q)logn(60^2))
o((n+q
)log
n(60
2)),而第一種則是o(n
+q)l
og2n
(602
))
o(n+q)log^2n(60^2))
o(n+q)
log2
n(60
2)),所以直接寫倍增吧,**如下:
#include
#include
#include
#define ll long long
using
namespace std;
const
int m=
2e4+10;
int n,m;
int jump[m][17
],dep[m]
;ll f[m][17
][62]
,lb[62]
;ll val[m]
;struct ss
}g[m<<1]
;int head[m]
,cnt;
void
add(
int a,
int b)
void
insert
(ll *a,ll x)
else x^
=a[i];}
//線性基插入
}void
merge
(ll *a,ll *b)
//線性基合併
void
dfs(
int a,
int fa)
for(
int i=head[a]
;i;i=g[i]
.last)
}//倍增
intlca
(int a,
int b)
if(a==b)
return a;
for(
int i=
16;i>=
0;i--)}
merge
(lb,f[a][0
]);insert
(lb,val[b]);
return jump[a][0
];}ll a;
int b,c;
void
file()
void
close()
intmain()
for(
int i=
1;i)dfs(1
,0);
while
(m--
)close()
;return0;
}
SCOI 2016 幸運數字 題解
題目傳送門 題目大意 有一棵樹,點帶權,每次問如何從 x xx 到 y yy 路徑上的點中選擇一些點使得他們的權值的異或和最大,輸出這個最大的異或和。從一些值中選擇一些值,使得他們的異或和最大,顯然就是線性基呀!那要求一條路徑的線性基,用 lca lcalc a 即可,開個結構體 f ff,f i ...
SCOI2016 幸運數字
線性基合併o log 2n 不能更小 但是倍增o qlog 3n 可過233333 甚至樹剖o qlog 4n 可過666666 還有乙個樹上路徑查詢利器 點分治!詢問離線 列舉重心,處理路徑過重心的詢問 邊dfs邊插入線性基,維護每個點到根路徑上的線性基 每個詢問,如果所屬不同的子樹,那麼過當前重...
SCOI2016 幸運數字
不想說了.就樹上的線性基合併.但是講道理o nlogn 3 為什麼能過去呢.但是就是能過去啊,因為博主是菜雞不怎麼會澱粉質啊,所以本篇題解只能提供這個複雜度的演算法了qaq 求選出來一些數使得異或和最大?線性基啊!那怎麼求路徑上的呢?乙個乙個往上合併,一直合併到lca就行了吧!乙個乙個合併顯然不行,...