板子
回滚并查集¶
struct Roll_DSU{
struct Data {
int son, fa, sizson, sizfa, fson;
LL sum;
} st[maxn];
int top;
// 撤销栈
int fa[maxn],siz[maxn];
LL sum;
void clear(){
// iota 递增赋值
std::iota(fa+1,fa+1+n,1),std::fill(siz+1,siz+1+n,1);
sum=0;
}
int find(int x){
return x == fa[x] ? x : find(fa[x]);
}
void merge(int x, int y) {
x=find(x), y=find(y);
if (x == y) return;
LL lst = sum;
sum += 1ll * siz[x] * siz[y]; // 答案--连通的点对数量 (按需修改)
if (siz[x] < siz[y])
st[++top] = { x, y, siz[x], siz[y], fa[x], lst }, fa[x] = y, siz[y] += siz[x];
else
st[++top] = { y, x, siz[y], siz[x], fa[y], lst }, fa[y] = x, siz[x] += siz[y];
}
void rollback(){
Data &t = st[top];
fa[t.son]=t.fson, siz[t.son]=t.sizson, siz[t.fa]=t.sizfa, sum=t.sum;
top--;
}
}dsu;
线性基¶
堪比高斯消元的动态线性基,from Menci。性质同高斯消元。
LL num[70];
void insert(LL x) {
for(int i=63;i>=0;i--){
if(!((x>>i)&1)) continue;
if(num[i]) x^=num[i];
else{
// 在该位插入 并消元 能达到和高斯消元一样的效果
// 用 a[0...i - 1] 消去 x 的第 [0, i - 1] 位上的 1
for(int j=0;j<i;j++) if((x>>j)&1) x^=num[j];
// 用 x 消去 a[i + 1, 60] 的第 i 位上的 1
for(int j=i+1;j<=63;j++) if((num[j]>>i)&1) num[j]^=x;
num[i]=x;
return ;
}
}
}
从中选任意多个数与某个数的异或最大值:
LL qry(LL x) {
LL res=x;
for (int i=63;i>=0;i--)
if ((res^num[i])>res)
res^=num[i];
return res;
}
01-trie¶
大端序:高位向低位建,用于算选一个数与某个数取 xor-max:
// 0-1 trie
// 高位向低位建 高位向低位贪心
struct Trie01{
int ch[maxn*63][2],cnt=1;
void ins(LL x){
int now=1;
for(int i=63;i>=0;i--){
int c=(x>>i)&1;
if(!ch[now][c]) ch[now][c]=++cnt;
now = ch[now][c];
}
}
LL getmax(LL x){ // x能异或出的最大值
LL res=0;
int now=1;
for(int i=63;i>=0;i--){
int c=(x>>i)&1;
if(ch[now][c^1]) now=ch[now][c^1], res|=(1ll<<i);
else now=ch[now][c];
}
return res;
}
}t;
哈希表¶
请注意 0xfffff 是要严格比 maxn 小的二进制全1的数
struct MyHash {
int operator()(ull key) {
return (key % maxn + maxn) % maxn;
}
int operator()(int key) {
return (key ^ key << 2 ^ key >> 3) & 0xfffff;
}
int operator()(const std::string& key) {
return key.length();
}
// ...
};
template<typename _k, typename _v, typename _hash = MyHash>
struct hash_map {
struct Data {
_k key;
_v val;
int pre; // 链式前向星
} e[maxn];
int tot, head[maxn];
void clear() {
while (tot) head[_hash()(e[tot].key)] = 0, tot--;
}
_v& operator[](_k key) {
int now = _hash()(key);
for (int p = head[now]; p; p = e[p].pre) if (e[p].key == key) return e[p].val;
// 否则新建
e[++tot] = {key, _v(), head[now]}, head[now] = tot;
return e[tot].val;
}
};
一般的 ull -> int 哈希表:
const int maxn = 1e5+10;
struct hash_map{
struct Data{
ull key;
int val,pre;
}e[maxn];
int head[maxn], tot;
int hash(ull key){
return (key ^ key<<2 ^ key>>3) & 0xfffff;
}
void clear(){
while(tot) head[hash(e[tot].key)]=0, tot--;
}
int& operator[](ull key){
int now=hash(key);
for(int p=head[now];p;p=e[p].pre) if(e[p].key == key) return e[p].val;
e[++tot]={key,0,head[now]}, head[now]=tot;
return e[tot].val;
}
};
其实就是链式前向星。。。
点分树¶
#include <bits/stdc++.h>
using LL = long long;
using std::cin;
using std::cout;
const int maxn = 1e5+10;
struct Edge{
int v,pre;
}e[maxn*2];
int head[maxn],tot;
void add(int u,int v){
e[++tot]={v,head[u]},head[u]=tot;
}
// find weight
// mxsiz::最大子树大小 mxsiz最小的点是重心 别忘了0初始化
// sumsiz::当前的分治子树大小
int siz[maxn],mxsiz[maxn],cen,sumsiz;
bool vis[maxn];
void getcen(int now,int fa) {
siz[now]=1;
mxsiz[now]=0;
for(int p=head[now]; p; p=e[p].pre) {
int v=e[p].v;
if(v==fa || vis[v]) continue;
getcen(v,now);
siz[now]+=siz[v];
mxsiz[now]=std::max(mxsiz[now],siz[v]);
}
mxsiz[now] = std::max(mxsiz[now],sumsiz-siz[now]); // 向上的树大小
if(mxsiz[now] <= mxsiz[cen]) cen=now; // 如果揉到一起写,必须小于等于
}
// 点分树上父亲
int _f[maxn];
void build(int now){
vis[now]=1;
// dfs to calc here
for(int p=head[now];p;p=e[p].pre){
int v=e[p].v;
if(v==_f[now] || vis[v]) continue;
sumsiz=siz[v], cen=0;
getcen(v,now),getcen(cen,0);
_f[cen]=now, build(cen);
}
}
int main(){
int n,m;
cin >> n >> m;
for(int i=1;i<n;i++) {
int u,v;
cin >> u >> v;
add(u,v),add(v,u);
}
sumsiz=n,mxsiz[cen=0]=INT_MAX;
getcen(1,0),getcen(cen,0);
build(cen);
return 0;
}
李超线段树¶
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using LL = long long;
using ull = unsigned long long;
using ld = long double;
const int maxn = 4e5+10; // 总线段
const int maxm=39990; // 值域
const ld eps = 1e-7;
int n;
bool eq(ld x,ld y) {
return fabsl(x-y)<eps;
}
struct Seg {
ld k,b;
int l,r;
int id;
ld operator()(int x) const {
if(l<=x && x<=r) return k*x+b;
else return -INFINITY;
// if max, it's -INF; or, it's INF.
// make sure you won't choose illegal segs
}
} t[maxm<<2];
**define**{: #define .hash} lid id<<1
**define**{: #define .hash} rid id<<1|1
// 向下标记
//void upd(int id,int l,int r,Seg f) {
// Seg &now = t[id];
// int mid=l+r>>1;
// // 根据mid上的取值进行分讨,tag存mid上最优的线段
// if(f(mid) > now(mid)) {
// // 先看自己更不更新
// if(now(l) > f(l)) upd(lid,l,mid,now);
// if(now(r) > f(r)) upd(rid,mid+1,r,now);
// // 说明原来存的线段还有利用价值(now在交点以外的部分仍然更优)
// // 接着向下改
// now = f;
// } else {
// if(f(l) > now(l)) upd(lid,l,mid,f);
// if(f(r) > now(r)) upd(rid,mid+1,r,f);
// }
//}
void upd(int id,int l,int r,Seg f) {
Seg &now = t[id];
int mid=l+r>>1;
if(f(mid) > now(mid)) std::swap(now,f); // 动态开点这么写就寄了,只能swap线段的k和b(要保证f的ls/rs=0)
if(f(l) > now(l)) upd(lid,l,mid,f);
if(f(r) > now(r)) upd(rid,mid+1,r,f);
}
// 返回线段(如有需要可以在Seg里打上id)
// 注意是标记永久化,每一层都要和自己t[id]取个max/min
Seg smax(const Seg& a,const Seg& b,int x) {
if(a(x) > b(x)) return a;
else return b;
}
Seg qry(int id,int l,int r,int pos) {
if(l==r) return t[id];
int mid=l+r>>1;
if(pos<=mid) return smax(t[id],qry(lid,l,mid,pos),pos);
else return smax(t[id],qry(rid,mid+1,r,pos),pos);
}
void join(int id,int l,int r,int ll,int rr,Seg i) {
if(l==ll && r==rr) {
upd(id,l,r,i);
return ;
}
int mid=l+r>>1;
if(rr<=mid) join(lid,l,mid,ll,rr,i);
else if(ll>mid) join(rid,mid+1,r,ll,rr,i);
else join(lid,l,mid,ll,mid,i),join(rid,mid+1,r,mid+1,rr,i);
}
// 李超树合并优化dp
// 动态开点!
**define**{: #define .hash} lid t[id].ls
**define**{: #define .hash} rid t[id].rs
int merge(int id, int y, int l, int r) {
if (!id || !y) return id + y;
upd(id, l, r, t[y]);
int mid = l+r>>1;
lid = merge(lid, t[y].ls, l, mid);
rid = merge(rid, t[y].rs, mid + 1, r);
return id;
}
/*
if(x0==x1) {
k = {0,std::max(y0,y1),x0,x0,tot};
} else {
k.k=1.0L*(y1-y0)/(x1-x0);
k.b=1.0L*y1-k.k*x1;
k.l= std::min(x0,x1);
k.r= std::max(x0,x1);
k.id=tot;
}
*/
分解质因数¶
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using LL = long long;
using ull = unsigned long long;
using ld = long double;
const int maxn = 1e7+10;
std::bitset<maxn> np;
int prime[maxn],cnt;
int x;
int main() {
np[1]=1;
for(int i=2; i<maxn; i++) {
if(!np[i]){
prime[++cnt]=i;
for(int j=i+i; j<maxn; j+=i) np[j]=1;
}
}
cin >> x;
int i=1;
while(i<=cnt && x!=1){
while(x%prime[i]) i++;
cout << prime[i] << '*';
x/=prime[i];
}
return 0;
}