==模板==
快读:
ll rd()
{
ll a=0;int f=0;char p=getchar();
while(!isdigit(p)){f|=p=='-';p=getchar();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
return f?-a:a;
}
组合数:
ll euclid(ll a, ll b, ll &x, ll &y) {
if (!b) return x = 1, y = 0, a;
ll d = euclid(b, a % b, y, x);
return y -= a/b * x, d;
}
struct mint {
ll x;
mint() :x(0){}
mint(ll xx) : x(xx) {}
operator ll(){return x;}
mint operator+(mint b) { return mint((x + b.x) % P); }
mint operator-(mint b) { return mint((x - b.x + P) % P); }
mint operator*(mint b) { return mint((x * b.x) % P); }
mint operator/(mint b) { return *this * invert(b); }
mint invert(mint a) {
ll x, y, g = euclid(a.x, P, x, y);
assert(g == 1); return mint((x + P) % P);
}
mint operator^(ll e) {
if (!e) return mint(1);
mint r = *this ^ (e / 2); r = r * r;
return e&1 ? *this * r : r;
}
};
mint fac[N],inv[N];
mint ksm(mint u,int v){
mint res=1;
while(v){
if(v&1) res=(ll)res*u%P;
v>>=1; u=(ll)u*u%P;
}
return res;
}
mint C(int n,int m){
if(n<m||m<0) return mint(0);
return fac[n]*inv[m]*inv[n-m];
}
mint S(int n,int m){
mint res=0;
for(int i=0;i<=m;++i){
mint tmp=(ll)ksm(m-i,n)*inv[i]%P*inv[m-i]%P;
if(i&1) res=res-tmp;
else res=res+tmp;
}
return res;
}
void C_init(mint n){
fac[0]=1;
for(int i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%P;
inv[n]=ksm(fac[n],P-2);
for(int i=n;i>=1;--i) inv[i-1]=(ll)inv[i]*i%P;
}
树状数组:
struct BIT
{
int n;
vector<int >c;
BIT(){}
BIT(int n){init(n);}
void init(int n){this->n=n;c.resize(n+1,0);}
void add(int u,int v){for(;u<=n;u+=u&-u) c[u]=(c[u]+v)%P;}
int ask(int u){int res=0;for(;u;u-=u&-u) res=(res+c[u])%P; return res;}
void add(int l,int r,int v){add(l,v); add(r+1,P-v);}
int ask(int l,int r){return (ask(r)-ask(l-1)+P)%P;}
};
template<class T>
struct BIT
{
int n;
vector<T >c;
BIT(){}
BIT(int n){init(n);}
void init(int n){this->n=n;c.resize(n+1,T{});}
void add(int u,T v){for(;u<=n;u+=u&-u) c[u]=c[u]+v;}
T ask(int u){T res=0;for(;u;u-=u&-u) res=res+c[u]; return res;}
void add(int l,int r,T v){add(l,v); add(r+1,-v);}
T ask(int l,int r){return ask(r)-ask(l-1);}
void clear(int u){for(;u<=n;u+=u&-u) c[u]=T{};}
};
struct B{
BIT<ll >T1,T2;
//B(int n){T1.init(n),T2.init(n);}
vector<int >c;
void init(int n){
T1.init(n);
T2.init(n);
c.resize(n+1,0);
}
void clear(int l,int r){
T1.clear(l,r);
T2.clear(l,r);
}
void add(int l,int r,ll v){
v%=P; r++;
T1.add(l,v);
T1.add(r,P-v);
T2.add(l,(ll)v*(1-l+P)%P);
T2.add(r,(ll)(P-v)*(1-r+P)%P);
}
int ask(int l,int r){
l--;
int A=T1.ask(r)%P*r%P;
int B=T1.ask(l)%P*l%P;
int C=T2.ask(r)%P;
int D=T2.ask(l)%P;
int AB=(A-B+P)%P;
int CD=(C-D+P)%P;
return (AB+CD)%P;
}
}T1,T2;
ST表:
struct node{
int n,s;
vector<vector<int > >st;
void init(int n,int val[]){
this->n=n;
this->s=log2(n);
st.resize(n+1,vector(s+1,0));
for(int i=1;i<=n;++i) st[i][0]=val[i];
for(int k=1;k<=s;++k){
for(int i=1;i+(1<<k)-1<=n;++i){
st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
}
}
}
int query(int l,int r){
int k=log2(r-l+1);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
}ST;
线段树:
#define ls u<<1
#define rs u<<1|1
#define ll long long
const int N = 2e5 + 5;
struct Msg {
ll sum; // 区间和
int len; // 区间长度
Msg() : sum(0), len(0) {}
Msg(ll S, int L) : sum(S), len(L) {}
Msg operator + (const Msg &p) const {
return Msg(sum + p.sum, len + p.len);
}
};
struct Tag {
ll add;
Tag() : add(0) {}
Tag(ll V) : add(V) {}
operator bool() const { return add != 0; }
Tag apply(const Tag &p) const {
return Tag(add + p.add);
}
Msg apply(const Msg &m) const {
return Msg(m.sum + add * m.len, m.len);
}
};
Msg msg[N << 2];
Tag tag[N << 2];
void apply(int u, Tag t) {
msg[u] = t.apply(msg[u]);
tag[u] = t.apply(tag[u]);
}
void pushdown(int u) {
if (!tag[u]) return;
apply(ls, tag[u]);
apply(rs, tag[u]);
tag[u] = Tag();
}
void pushup(int u) {
msg[u] = msg[ls] + msg[rs];
}
void build(int u, int l, int r) {
tag[u] = Tag();
if (l == r) {
msg[u] = Msg(0, 1);
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int L, int R, Tag t) {
if (L <= l && r <= R) {
apply(u, t);
return;
}
int mid = (l + r) >> 1;
pushdown(u);
if (L <= mid) modify(ls, l, mid, L, R, t);
if (R > mid) modify(rs, mid + 1, r, L, R, t);
pushup(u);
}
Msg query(int u, int l, int r, int L, int R) {
if (L <= l && r <= R) {
return msg[u];
}
int mid = (l + r) >> 1;
pushdown(u);
Msg res = Msg();
if (L <= mid) res = res + query(ls, l, mid, L, R);
if (R > mid) res = res + query(rs, mid + 1, r, L, R);
return res;
}
struct SMT//区间更新,区间最大值
{
int n;
vector<int >c1,c2;
SMT(){}
SMT(int n){init(n);}
void init(int n){this->n=n;
c1.clear();c1.resize(n<<2);
c2.clear();c2.resize(n<<2);
}
void modify(int u,int l,int r,int L,int R,int x){
c2[u]=max(c2[u],x);
if(L<=l&&r<=R){c1[u]=max(c1[u],x);return ;}
int mid=(l+r)>>1;
if(L<=mid) modify(ls,l,mid,L,R,x);
if(R>mid) modify(rs,mid+1,r,L,R,x);
}
int query(int u,int l,int r,int L,int R){
if(L<=l&&r<=R) return max(c1[u],c2[u]);
int mid=(l+r)>>1; int res=c1[u];
if(L<=mid) res=max(res,query(ls,l,mid,L,R));
if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
return res;
}
}T;
struct SEGT{//单点修改,区间加,区间最大值
ll mx[N],tag[N];
void pushup(int u){
mx[u]=max(mx[ls],mx[rs]);
}
void pushdown(int u){
mx[ls]+=tag[u]; tag[ls]+=tag[u];
mx[rs]+=tag[u]; tag[rs]+=tag[u];
tag[u]=0;
}
void build(int u,int l,int r){
mx[u]=-1e18; tag[u]=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void modify(int u,int l,int r,int x,ll v){//单点修改
if(l==r){
mx[u]=v;
return ;
}
int mid=(l+r)>>1; pushdown(u);
if(x<=mid) modify(ls,l,mid,x,v);
else modify(rs,mid+1,r,x,v);
pushup(u);
}
void add(int u,int l,int r,int L,int R,ll v){//区间加
if(L<=l&&r<=R){
tag[u]+=v;
mx[u]+=v;
return ;
}
int mid=(l+r)>>1; pushdown(u);
if(L<=mid) add(ls,l,mid,L,R,v);
if(R>mid) add(rs,mid+1,r,L,R,v);
pushup(u);
}
ll query(int u,int l,int r,int L,int R){//区间最大值
if(L<=l&&r<=R) return mx[u];
int mid=(l+r)>>1; pushdown(u); ll res=-1e18;
if(L<=mid) res=max(res,query(ls,l,mid,L,R));
if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
return res;
}
}T;
并查集:
struct DSU {
std::vector<int> f, siz;
DSU() {}
DSU(int n) {init(n);}
void init(int n) {
f.resize(n);
std::iota(f.begin(), f.end(), 0);
siz.assign(n, 1);
}
int find(int x) {
while (x != f[x]) {
x = f[x] = f[f[x]];
}
return x;
}
bool same(int x, int y) {
return find(x) == find(y);
}
bool merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return false;
}
siz[x] += siz[y];
f[y] = x;
return true;
}
int size(int x) {
return siz[find(x)];
}
};
欧拉回路:
vector<int >G[N];
int t[N],top;
bool visp[N],vise[N];
void dfs(int u){
t[top++]=u;
if(visp[u]) return ;
visp[u]=true;
for(auto ed:G[u]){
if(vise[ed]) continue;
vise[ed]=true;
dfs(sum[ed]^u);
t[top++]=u;
}
}
//最后top--
void euler(int u)
{
while(!G[u].empty())
{
int w=G[u].back();
G[u].pop_back();
int v=edg[w]^u;
if(!vis[w]) continue;
vis[w]=false;
euler(v);
}
cout<<u+1<<" ";
}
矩阵:
const int M=64;
struct Mat{
ll mat[M][M];
Mat(){memset(mat,0,sizeof(Mat));}
void reset(){
for(int i=0;i<M;++i) mat[i][i]=1;
}
ll* operator [](ll p){return mat[p];}
Mat operator *(const Mat &ot)const{
Mat res;
for(int k=0;k<M;++k)
for(int i=0;i<M;++i){
if(!mat[i][k]) continue;
for(int j=0;j<M;++j)
res[i][j]=(res[i][j]+mat[i][k]*ot.mat[k][j])%P;
}
return res;
}
Mat operator +(const Mat &ot)const{
Mat res;
for(int i=0;i<M;++i)
for(int j=0;j<M;++j)
res.mat[i][j]=(mat[i][j]+ot.mat[i][j])%P;
return res;
}
};
矩阵求行列式
Z det(vector<vector<Z>> a) {
int n = sz(a);
Z res = 1;
for (int i = 0; i < n; i++) {
int k = i;
while (k < n && a[k][i] == 0) k++;
if (k == n) return Z(0);
if (k != i) {
swap(a[i], a[k]);
res = -res;
}
res *= a[i][i];
Z inv = a[i][i].inv();
for (int j = i + 1; j < n; j++) {
if (a[j][i].v == 0) continue;
Z div = a[j][i] * inv;
for (int l = i; l < n; l++) {
a[j][l] -= a[i][l] * div;
}
}
}
return res;
}
最大流/最小割:
template<class T>
struct MaxFlow {
struct _Edge {
int to;
T cap;
_Edge(int to, T cap) : to(to), cap(cap) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<int> cur, h;
MaxFlow() {}
MaxFlow(int n) {
init(n);
}
void init(int n) {
this->n = n;
e.clear();
g.assign(n, {});
cur.resize(n);
h.resize(n);
}
bool bfs(int s, int t) {
h.assign(n, -1);
std::queue<int> que;
h[s] = 0;
que.push(s);
while (!que.empty()) {
const int u = que.front();
que.pop();
for (int i : g[u]) {
auto [v, c] = e[i];
if (c > 0 && h[v] == -1) {
h[v] = h[u] + 1;
if (v == t) {
return true;
}
que.push(v);
}
}
}
return false;
}
T dfs(int u, int t, T f) {
if (u == t) {
return f;
}
auto r = f;
for (int &i = cur[u]; i < int(g[u].size()); ++i) {
const int j = g[u][i];
//auto [v, c] = e[j];
int v = e[j].to;
T c = e[j].cap;
if (c > 0 && h[v] == h[u] + 1) {
auto a = dfs(v, t, std::min(r, c));
e[j].cap -= a;
e[j ^ 1].cap += a;
r -= a;
if (r == 0) {
return f;
}
}
}
return f - r;
}
void addEdge(int u, int v, T c) {
g[u].push_back(e.size());
e.emplace_back(v, c);
g[v].push_back(e.size());
e.emplace_back(u, 0);
}
T flow(int s, int t) {
T ans = 0;
while (bfs(s, t)) {
cur.assign(n, 0);
ans += dfs(s, t, std::numeric_limits<T>::max());
}
return ans;
}
std::vector<bool> minCut() {
std::vector<bool> c(n);
for (int i = 0; i < n; i++) {
c[i] = (h[i] != -1);
}
return c;
}
struct Edge {
int from;
int to;
T cap;
T flow;
};
std::vector<Edge> edges() {
std::vector<Edge> a;
for (int i = 0; i < e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.flow = e[i + 1].cap;
a.push_back(x);
}
return a;
}
};
有源汇上下界最大流/最小流(结合上个模板一起食用)
template<class T>
struct LBoundSTFlow {
struct EdgeRec { int u,v; T L,U; };
int n, SS, TT, s_, t_;
MaxFlow<T> mf;
std::vector<EdgeRec> rec;
std::vector<T> bal;
int id_ts;
LBoundSTFlow() {}
LBoundSTFlow(int n_) { init(n_); }
void init(int n_) {
n = n_;
SS = n;
TT = n + 1;
mf.init(n + 2);
rec.clear();
bal.assign(n, 0);
id_ts = -1;
s_ = t_ = -1;
}
void addEdge(int u,int v,T L,T U){
rec.push_back({u,v,L,U});
}
void build_base() {
mf.init(n + 2);
bal.assign(n, 0);
for (auto &e: rec) {
mf.addEdge(e.u, e.v, e.U - e.L);
bal[e.u] -= e.L;
bal[e.v] += e.L;
}
}
T add_demands_and_return_need() {
T need = 0;
for (int i = 0; i < n; ++i) {
if (bal[i] > 0) { mf.addEdge(SS, i, bal[i]); need += bal[i]; }
else if (bal[i] < 0) { mf.addEdge(i, TT, -bal[i]); }
}
return need;
}
bool feasible_with_ts(int s,int t,T capTS){
s_=s; t_=t;
build_base();
T need = add_demands_and_return_need();
id_ts = (int)mf.e.size();
mf.addEdge(t, s, capTS);
T got = mf.flow(SS, TT);
return got == need;
}
std::pair<bool,T> maxflow(int s,int t){
const T INF = std::numeric_limits<T>::max() / 4;
if (!feasible_with_ts(s,t,INF)) return {false, (T)0};
T base = mf.e[id_ts ^ 1].cap;
mf.e[id_ts].cap = 0;
mf.e[id_ts ^ 1].cap = 0;
T extra = mf.flow(s, t);
return {true, base + extra};
}
std::pair<bool,T> minflow(int s,int t){
const T INF = std::numeric_limits<T>::max() / 4;
if (!feasible_with_ts(s,t,INF)) return {false, (T)0};
T base = mf.e[id_ts ^ 1].cap;
mf.e[id_ts].cap = 0;
mf.e[id_ts ^ 1].cap = 0;
T can_reduce = mf.flow(t, s);
return {true, base - can_reduce};
}
};
//用法:先 init(n),对每条边 addEdge(u,v,L,U);然后 maxflow(s,t) 或 minflow(s,t)。
//返回:{ok, value},ok=false 表示无可行流。
最小费最大流:
template<class T>
struct MinCostFlow {
struct _Edge {
int to;
T cap;
T cost;
_Edge(int to_, T cap_, T cost_) : to(to_), cap(cap_), cost(cost_) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<T> h, dis;
std::vector<int> pre;
bool dijkstra(int s, int t) {
const T INF = std::numeric_limits<T>::max();
dis.assign(n, INF);
pre.assign(n, -1);
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<std::pair<T, int>>> que;
dis[s] = 0;
que.emplace(0, s);
while (!que.empty()) {
auto [d, u] = que.top();
que.pop();
if (dis[u] != d) continue;
for (int i : g[u]) {
int v = e[i].to;
T cap = e[i].cap;
T cost = e[i].cost;
if (cap > 0) {
T nd = d + h[u] - h[v] + cost;
if (nd < dis[v]) {
dis[v] = nd;
pre[v] = i;
que.emplace(nd, v);
}
}
}
}
return dis[t] != INF;
}
bool spfa_init(int s) {
const T INF = std::numeric_limits<T>::max();
h.assign(n, INF);
std::vector<char> inq(n, 0);
std::queue<int> q;
h[s] = 0;
q.push(s);
inq[s] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
inq[u] = 0;
T hu = h[u];
for (int i : g[u]) {
if (e[i].cap <= 0) continue;
int v = e[i].to;
T w = e[i].cost;
if (hu != INF && h[v] > hu + w) {
h[v] = hu + w;
if (!inq[v]) { q.push(v); inq[v] = 1; }
}
}
}
for (int i = 0; i < n; ++i) if (h[i] == INF) h[i] = 0;
return true;
}
MinCostFlow() {}
MinCostFlow(int n_) { init(n_); }
void init(int n_) {
n = n_;
e.clear();
g.assign(n, {});
}
void addEdge(int u, int v, T cap, T cost) {
g[u].push_back(e.size());
e.emplace_back(v, cap, cost);
g[v].push_back(e.size());
e.emplace_back(u, 0, -cost);
}
std::pair<T, T> flow(int s, int t) {
T flow = 0, cost = 0;
spfa_init(s);
while (dijkstra(s, t)) {
for (int i = 0; i < n; ++i) if (dis[i] != std::numeric_limits<T>::max()) h[i] += dis[i];
T aug = std::numeric_limits<T>::max();
for (int v = t; v != s; v = e[pre[v] ^ 1].to) aug = std::min(aug, e[pre[v]].cap);
for (int v = t; v != s; v = e[pre[v] ^ 1].to) {
e[pre[v]].cap -= aug;
e[pre[v] ^ 1].cap += aug;
}
flow += aug;
cost += aug * h[t];
}
return {flow, cost};
}
struct Edge {
int from;
int to;
T cap;
T cost;
T flow;
};
std::vector<Edge> edges() {
std::vector<Edge> a;
for (int i = 0; i < (int)e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.cost = e[i].cost;
x.flow = e[i + 1].cap;
a.push_back(x);
}
return a;
}
};
//时间复杂度:O(VE+F⋅(ElogV))
//前面是预处理势能的spfa时间复杂度
//后面是F(最大流)*每次dijkstra的E(边数)logV
点分治:
bool vis[N];
int siz[N],mx[N],root;
void get_root(int u,int tot){
vis[u]=true;
siz[u]=1; mx[u]=0;
for(auto v:G[u]){
if(vis[v]) continue;
get_root(v,tot);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u],tot-siz[u]);
if(root==-1||mx[u]<mx[root]) root=u;
vis[u]=false;
}
void dfs(int u){
vis[u]=true;
for(auto v:G[u]){
if(vis[v]) continue;
dfs(v);
}
vis[u]=false;
}
void dvq(int u,int tot){
root=-1;
get_root(u,tot);
dfs(root);
vis[root]=true;
for(auto v:G[root]){
if(vis[v]) continue;
dvq(v,siz[v]<siz[root]? siz[v]:tot-siz[root]);
}
}
点分树:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll rd() {
ll x = 0; int f = 0; char c = getchar();
while (!isdigit(c)) { if (c == '-') f = 1; c = getchar(); }
while (isdigit(c)) { x = x * 10 + (c - '0'); c = getchar(); }
return f ? -x : x;
}
const int MAXN = 100000 + 5;
vector<int> g[MAXN];
int sz[MAXN], par_cent[MAXN], level_cent[MAXN], dist_cent[17][MAXN], ans[MAXN];
bool used[MAXN];
int n, m;
int dfs_sz(int u, int p) {
sz[u] = 1;
for (int v : g[u]) if (v != p && !used[v]) sz[u] += dfs_sz(v, u);
return sz[u];
}
int get_centroid(int u, int p, int tot) {
for (int v : g[u]) if (v != p && !used[v])
if (sz[v] > tot / 2) return get_centroid(v, u, tot);
return u;
}
void dfs_dist(int u, int p, int lvl, int d) {
dist_cent[lvl][u] = d;
for (int v : g[u]) if (v != p && !used[v]) dfs_dist(v, u, lvl, d + 1);
}
void build(int u, int p) {
int tot = dfs_sz(u, -1);
int c = get_centroid(u, -1, tot);
par_cent[c] = (p == -1 ? c : p);
level_cent[c] = (p == -1 ? 0 : level_cent[p] + 1);
dfs_dist(c, -1, level_cent[c], 0);
used[c] = true;
for (int v : g[c]) if (!used[v]) build(v, c);
}
void update(int u) {
for (int x = u; ; x = par_cent[x]) {
ans[x] = min(ans[x], dist_cent[level_cent[x]][u]);
if (x == par_cent[x]) break;
}
}
int query(int u) {
int res = INT_MAX;
for (int x = u; ; x = par_cent[x]) {
res = min(res, ans[x] + dist_cent[level_cent[x]][u]);
if (x == par_cent[x]) break;
}
return res;
}
int main() {
n = rd(); m = rd();
for (int i = 1; i <= n; i++) {
g[i].clear();
used[i] = false;
}
for (int i = 1; i < n; i++) {
int u = rd(), v = rd();
g[u].push_back(v);
g[v].push_back(u);
}
build(1, -1);
const int INF = 1e9;
for (int i = 1; i <= n; i++) ans[i] = INF;
update(1);
while (m--) {
int t = rd(), v = rd();
if (t == 1) update(v);
else printf("%d\n", query(v));
}
return 0;
}
李超线段树:
struct Tree//李超树
{
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
struct Node
{
ll a,b;
}tree[600005];
void ins(int x,int l,int r,ll a,ll b)//插入一个一次函数
{
if(tree[x].a*l+tree[x].b<=a*l+b&&tree[x].a*r+tree[x].b<=a*r+b)
{
tree[x].a=a,tree[x].b=b;
return;
}
if(tree[x].a*l+tree[x].b>=a*l+b&&tree[x].a*r+tree[x].b>=a*r+b)return;
if(tree[x].a*mid+tree[x].b<a*mid+b)swap(tree[x].a,a),swap(tree[x].b,b);
if(a<tree[x].a)ins(lc,l,mid,a,b);
else ins(rc,mid+1,r,a,b);//比较中间值,然后单边递归
}
void build(int x,int l,int r)
{
tree[x].a=tree[x].b=0;
if(l==r)return;
build(lc,l,mid);
build(rc,mid+1,r);
}
ll query(int x,int l,int r,int p)//查询单点最大值,因为标记永久化所以需要一路取max
{
ll ans=tree[x].a*p+tree[x].b;
if(l==r)return ans;
if(p<=mid)ans=max(ans,query(lc,l,mid,p));
else ans=max(ans,query(rc,mid+1,r,p));
return ans;
}
#undef lc
#undef rc
#undef mid
}T;
//
struct LiChao {
struct Line { ll m,b; Line(ll _m=0,ll _b=LLONG_MIN):m(_m),b(_b){} };
struct Node { Line ln; Node *l,*r; Node(Line _ln):ln(_ln),l(nullptr),r(nullptr){} };
ll L,R; Node* root;
LiChao(ll _L,ll _R):L(_L),R(_R),root(nullptr){}
ll f(const Line& ln,ll x){ return ln.m*x + ln.b; }
void add(Line ln){ add_line(root,L,R,ln); }
void add_line(Node*& o,ll l,ll r,Line ln){
if(!o){ o=new Node(ln); return; }
ll mid=(l+r)>>1;
bool lef = f(ln,l) > f(o->ln,l);
bool md = f(ln,mid) > f(o->ln,mid);
if(md) swap(ln, o->ln);
if(l==r) return;
if(lef != md) add_line(o->l, l, mid, ln);
else add_line(o->r, mid+1, r, ln);
}
ll query(ll x){ return query(root,L,R,x); }
ll query(Node* o,ll l,ll r,ll x){
if(!o) return LLONG_MIN;
ll res = f(o->ln,x);
if(l==r) return res;
ll mid=(l+r)>>1;
if(x<=mid) return max(res, query(o->l, l, mid, x));
else return max(res, query(o->r, mid+1, r, x));
}
};
lichao.add(LiChao::Line(m,b));
lichao.query(a[i]);
几何:
struct Point{
ll x,y;
int u,v;
Point(){}
Point(ll X,ll Y){x=X;y=Y;}
Point(ll X,ll Y,int U,int V){x=X;y=Y;u=U;v=V;}
double theta(){
return atan2(y,x)<0? pi+pi+atan2(y,x):atan2(y,x);
}
Point operator - (const Point &P)const{
return Point(x-P.x,y-P.y);
}
Point operator + (const Point &P)const{
return Point(x+P.x,y+P.y);
}
ll operator * (const Point &P)const{
return x*P.y-y*P.x;
}//叉积 (三角形面积的两倍)
};
最近公共祖先LCA:
//树剖求LCA
int siz[N],dep[N],fa[N],mx_son[N];
int dfn[N],pre[N],top[N],tot;
int n,m,root,a[N];
vector<int >G[N];
void dfs1(int u,int f){
fa[u]=f;siz[u]=1;dep[u]=dep[f]+1;mx_son[u]=0;
for(auto v:G[u]){
if(v==f) continue;
dfs1(v,u);siz[u]+=siz[v];
if(siz[v]>siz[mx_son[u]])mx_son[u]=v;
}
}
void dfs2(int u,int f,int t){
top[u]=t;dfn[u]=++tot;pre[tot]=u;
if(mx_son[u]) dfs2(mx_son[u],u,t);
for(auto v:G[u]) if(v!=f&&v!=mx_son[u]) dfs2(v,u,v);
}
int LCA(int x,int y){
for(;top[x]!=top[y];x=fa[top[x]])if(dep[top[x]]<dep[top[y]])swap(x,y);
return dep[x]<dep[y]?x:y;
}
//倍增求LCA
void dfs1(int u,int f){
fa[u]=f; st[u][0]=f; dep[u]=dep[f]+1;
for(int k=1;k<20;++k) st[u][k]=st[st[u][k-1]][k-1];
for(auto v:G[u]){
if(v==f) continue;
dfs1(v,u);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int k=19;k>=0;--k)
if((dep[x]-dep[y])>>k&1) x=st[x][k];
if(x==y) return x;
for(int k=19;k>=0;--k)
if(st[x][k]!=st[y][k]) x=st[x][k],y=st[y][k];
return st[x][0];
}
分块:
namespace block{
int L[N],R[N],pos[N],B,tot;
ll val[N],sum[N];
void init(int n){
B=max((int)sqrt(n),3); tot=(n-1)/B+1;
for(int i=1;i<=n;++i) pos[i]=(i-1)/B+1;
for(int i=1;i<=tot;++i) L[i]=(i-1)*B+1,R[i]=min(n,i*B);
}
void modify(int p,int v){val[p]+=v;sum[pos[p]]+=v;}
ll query(int l,int r){
ll res=0;
if(pos[l]==pos[r]) for(int i=l;i<=r;++i) res+=val[i];
else{
for(int i=l;i<=R[pos[l]];++i) res+=val[i];
for(int i=pos[l]+1;i<pos[r];++i) res+=sum[i];
for(int i=L[pos[r]];i<=r;++i) res+=val[i];
}
return res;
}
}
字符串:
//双哈希
struct Hash {
ll mod1 = 1000000007;
ll mod2 = 1000000009;
ll base1 = 131;
ll base2 = 137;
vector<ll> h1, h2, p1, p2;
int n;
Hash(const string &s) {
n = s.size();
h1.assign(n + 1, 0);
h2.assign(n + 1, 0);
p1.assign(n + 1, 1);
p2.assign(n + 1, 1);
for (int i = 1; i <= n; i++) {
h1[i] = (h1[i - 1] * base1 + s[i - 1]) % mod1;
h2[i] = (h2[i - 1] * base2 + s[i - 1]) % mod2;
p1[i] = (p1[i - 1] * base1) % mod1;
p2[i] = (p2[i - 1] * base2) % mod2;
}
}
pair<ll, ll> get(int l, int r) {
ll x1 = (h1[r] - h1[l - 1] * p1[r - l + 1]) % mod1;
if (x1 < 0) x1 += mod1;
ll x2 = (h2[r] - h2[l - 1] * p2[r - l + 1]) % mod2;
if (x2 < 0) x2 += mod2;
return {x1, x2};
}
};
//AC自动机
namespace AC{
int fail[N],trie[N][S],rt=1,tot=1;
int insert(char *s){
int len=strlen(s+1),cur=rt;
for(int i=1;i<=len;++i){
if(!trie[cur][s[i]-'a']) trie[cur][s[i]-'a']=++tot;
cur=trie[cur][s[i]-'a']; nd[i]=cur;
}
return cur;
}
queue<int >q;
void build(){
for(int i=0;i<S;++i) trie[0][i]=1;
q.push(rt);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=0;i<S;++i){
int v=trie[u][i];
if(!v) trie[u][i]=trie[fail[u]][i];
else fail[v]=trie[fail[u]][i],q.push(v);
}
}
for(int i=2;i<=tot;++i) G[fail[i]].pub(i);
dfs1(1,0);
dfs2(1,0,1);
}
}
//后缀数组
int sa[N], rk_[N], height[N];
int x_[N], y_[N], c[N];
void build_sa(const string &s){
int n=sz(s), m=256;
for(int i=1;i<=n;++i) x_[i]=(unsigned char)s[i-1]+1;
for(int i=0;i<=m;++i) c[i]=0;
for(int i=1;i<=n;++i) ++c[x_[i]];
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i>=1;--i) sa[c[x_[i]]--]=i;
int p=0;
for(int k=1;p<n;k<<=1){
p=0;
for(int i=n-k+1;i<=n;++i) y_[++p]=i;
for(int i=1;i<=n;++i) if(sa[i]>k) y_[++p]=sa[i]-k;
for(int i=0;i<=m;++i) c[i]=0;
for(int i=1;i<=n;++i) ++c[x_[y_[i]]];
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i>=1;--i) sa[c[x_[y_[i]]]--]=y_[i];
for(int i=1;i<=n;++i) swap(x_[i],y_[i]);
x_[sa[1]]=p=1;
for(int i=2;i<=n;++i){
int a=sa[i], b=sa[i-1];
x_[a]=(y_[a]==y_[b] && (a+k<=n?y_[a+k]:0)==(b+k<=n?y_[b+k]:0))?p:++p;
}
m=p;
}
for(int i=1;i<=n;++i) rk_[sa[i]]=i;
for(int i=1,k=0;i<=n;++i){
if(rk_[i]==1){ k=0; continue; }
int j=sa[rk_[i]-1];
while(i+k<=n && j+k<=n && s[i-1+k]==s[j-1+k]) ++k;
height[rk_[i]]=k;
if(k) --k;
}
}
for(int i=1;i<=n;++i) cout<<sa[i]<<" \n"[i==n];
for(int i=1;i<=n;++i) cout<<height[i]<<" \n"[i==n];
//后缀自动机
int n,m,las=1,tot=1;
int trip[N][26];
int len[N],fa[N];
ll val[N];
void insert(int u,int v)
{
int p=las; int np=las=++tot; len[np]=len[p]+1; val[np]=v;
for(;p&&!trip[p][u];p=fa[p]) trip[p][u]=np;
if(!p) fa[np]=1;
else
{
int q=trip[p][u];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot; len[nq]=len[p]+1;
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
memcpy(trip[nq],trip[q],sizeof(trip[q]));
for(;p&&trip[p][u]==q;p=fa[p]) trip[p][u]=nq;
}
}
}
NTT:
struct Z{
static const int MOD = 998244353;
int v;
Z(long long x=0){x %= MOD;if(x < 0) x += MOD;v = int(x);}
operator long long() const { return v; }
explicit operator int() const { return v; }
Z& operator+=(const Z& o){v += o.v;if(v >= MOD) v -= MOD;return *this;}
Z& operator-=(const Z& o){v -= o.v;if(v < 0) v += MOD;return *this;}
Z& operator*=(const Z& o){v = int(1ll * v * o.v % MOD);return *this;}
Z& operator/=(const Z& o){return *this *= o.inv();}
friend Z operator+(Z a,const Z& b){ return a += b; }
friend Z operator-(Z a,const Z& b){ return a -= b; }
friend Z operator*(Z a,const Z& b){ return a *= b; }
friend Z operator/(Z a,const Z& b){ return a /= b; }
static Z qpow(Z a,long long e){Z r = 1;for(;e;e>>=1,a*=a) if(e&1) r *= a;return r;}
Z inv() const { return qpow(*this, MOD-2); }
};
Z ksm(Z u,long long v){return Z::qpow(u,v);}
Z ksm(int u,long long v){return Z::qpow(Z(u),v);}
/******** NTT与多项式工具 ********/
void ntt(std::vector<Z>& a,bool inv){
int n = (int)a.size();
static std::vector<int> rev;
static std::vector<Z> roots{0,1};
if((int)rev.size() != n){
int k = __lg(n);
rev.assign(n,0);
for(int i=0;i<n;i++){
rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
}
}
if((int)roots.size() < n){
int k = __lg((int)roots.size());
roots.resize(n);
while((1<<k) < n){
Z z = Z::qpow(3, (Z::MOD-1)>>(k+1));
for(int i=(1<<(k-1)); i<(1<<k); i++){
roots[2*i] = roots[i];
roots[2*i+1] = roots[i] * z;
}
k++;
}
}
for(int i=0;i<n;i++) if(i < rev[i]) std::swap(a[i],a[rev[i]]);
for(int len=1; len<n; len<<=1){
for(int i=0; i<n; i+=len<<1){
for(int j=0; j<len; j++){
Z u = a[i+j];
Z v = a[i+j+len] * roots[len+j];
a[i+j] = u + v;
a[i+j+len] = u - v;
}
}
}
if(inv){
std::reverse(a.begin()+1,a.end());
Z invn = Z(n).inv();
for(auto &x : a) x *= invn;
}
}
std::vector<Z> convolution(std::vector<Z> a, std::vector<Z> b){
if(a.empty() || b.empty()) return {};
int need = (int)a.size() + (int)b.size() - 1;
int n = 1;
while(n < need) n <<= 1;
a.resize(n);
b.resize(n);
ntt(a,false);
ntt(b,false);
for(int i=0;i<n;i++) a[i] *= b[i];
ntt(a,true);
a.resize(need);
return a;
}
std::vector<Z> poly_add(const std::vector<Z>& a,const std::vector<Z>& b){
std::vector<Z> c(std::max(a.size(),b.size()));
for(size_t i=0;i<c.size();i++){
Z x = 0, y = 0;
if(i < a.size()) x = a[i];
if(i < b.size()) y = b[i];
c[i] = x + y;
}
return c;
}
std::vector<Z> poly_sub(const std::vector<Z>& a,const std::vector<Z>& b){
std::vector<Z> c(std::max(a.size(),b.size()));
for(size_t i=0;i<c.size();i++){
Z x = 0, y = 0;
if(i < a.size()) x = a[i];
if(i < b.size()) y = b[i];
c[i] = x - y;
}
return c;
}
std::vector<Z> mod_xk(std::vector<Z> a,int k){
if((int)a.size() > k) a.resize(k);
return a;
}
std::vector<Z> div_xk(const std::vector<Z>& a,int k){
if(k >= (int)a.size()) return {};
return std::vector<Z>(a.begin()+k,a.end());
}
using poly = std::vector<Z>;
/******** 组合数 ********/
Z fac[N], inv[N];
void C_init(int n){
fac[0] = 1;
for(int i=1;i<=n;i++) fac[i] = fac[i-1] * Z(i);
inv[n] = fac[n].inv();
for(int i=n;i>=1;i--) inv[i-1] = inv[i] * Z(i);
}
Z C(int n,int m){
if(n < m || m < 0) return Z(0);
return fac[n] * inv[m] * inv[n-m];
}
Z S(int n,int m){
Z res = 0;
for(int i=0;i<=m;i++){
Z tmp = ksm(Z(m - i), n) * inv[i] * inv[m - i];
if(i & 1) res -= tmp;
else res += tmp;
}
return res;
}
FWT:
void or_fwt(int *nw,int opt)
{
for(int k=0;k<n;++k)
for(int i=0;i<(1<<n);++i)
{
if(i&(1<<k))
{
if(opt==1) nw[i]=(nw[i]+nw[i^(1<<k)])%P;
else nw[i]=(nw[i]-nw[i^(1<<k)]+P)%P;
}
}
}
void and_fwt(int *nw,int opt)
{
for(int k=0;k<n;++k)
for(int i=0;i<(1<<n);++i)
{
if((~i)&(1<<k))
{
if(opt==1) nw[i]=(nw[i]+nw[i^(1<<k)])%P;
else nw[i]=(nw[i]-nw[i^(1<<k)]+P)%P;
}
}
}
void xor_fwt(int *nw,int opt)
{
for(int k=0;k<n;++k)
for(int i=0;i<(1<<n);++i)
{
if(i&(1<<k))
{
int x=nw[i^(1<<k)]; int y=nw[i];
if(opt==1) nw[i^(1<<k)]=(x-y+P)%P,nw[i]=(x+y)%P;
else nw[i^(1<<k)]=(ll)(x+y)*inv2%P,nw[i]=(ll)(y-x+P)*inv2%P;
}
}
}
void or_solve()
{
for(int i=0;i<(1<<n);++i) f[i]=a[i];
for(int i=0;i<(1<<n);++i) g[i]=b[i];
or_fwt(f,1); or_fwt(g,1);
for(int i=0;i<(1<<n);++i) h[i]=(ll)f[i]*g[i]%P;
or_fwt(h,-1);
for(int i=0;i<(1<<n);++i) printf("%d ",h[i]);
puts("");
}
void and_solve()
{
for(int i=0;i<(1<<n);++i) f[i]=a[i];
for(int i=0;i<(1<<n);++i) g[i]=b[i];
and_fwt(f,1); and_fwt(g,1);
for(int i=0;i<(1<<n);++i) h[i]=(ll)f[i]*g[i]%P;
and_fwt(h,-1);
for(int i=0;i<(1<<n);++i) printf("%d ",h[i]);
puts("");
}
void xor_solve()
{
for(int i=0;i<(1<<n);++i) f[i]=a[i];
for(int i=0;i<(1<<n);++i) g[i]=b[i];
xor_fwt(f,1); xor_fwt(g,1);
for(int i=0;i<(1<<n);++i) h[i]=(ll)f[i]*g[i]%P;
xor_fwt(h,-1);
for(int i=0;i<(1<<n);++i) printf("%d ",h[i]);
puts("");
}
高斯消元:
#include<bits/stdc++.h>
using namespace std;
int n;
double s[105][105];
bool flag;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&s[i][j]);
for(int i=1;i<=n;i++)
{
int tmp=i;
for(int k=i+1;k<=n;k++)
if(abs(s[k][i])>abs(s[tmp][i]))
tmp=k;
for(int j=1;j<=n+1;j++)
swap(s[i][j],s[tmp][j]);
for(int j=1;j<=n;j++)
{
if(j==i)
continue;
double tmp=s[j][i]/s[i][i];
for(int k=1;k<=n+1;k++)
s[j][k]-=s[i][k]*tmp;
}
}
for(int i=1;i<=n;i++)
if(s[i][i]==0)
flag=true;
if(flag)
{
printf("No Solution");
return 0;
}
for(int i=1;i<=n;i++)
printf("%.2lf\n",s[i][n+1]/s[i][i]);
return 0;
}
扩展中国剩余定理:
ll exgcd(ll a, ll b, ll &x, ll &y) {
// 终止情况:如果 b 为 0,则 gcd(a, b) = a,且 x = 1, y = 0
if (b == 0) {
x = 1;
y = 0;
return a;
}
// 递归计算 gcd(b, a % b) 以及 x' 和 y'
ll x1, y1;
ll gcd = exgcd(b, a % b, x1, y1);
// 回溯计算 x 和 y
x = y1;
y = x1 - (a / b) * y1;
return gcd;
}
int main()
{
ll A=1; ll B=0;
int T=rd();
while(T--){
ll a=rd(); ll b=rd();
ll k1,k2;
ll gcd=exgcd(A,a,k1,k2);
if((b-B)%gcd) return 0;//无解(题目保证有解)
ll lcm=A/gcd*a;
ll k=(b-B)/gcd;
k=(k%lcm+lcm)%lcm;
k1=(k1%lcm+lcm)%lcm;
k2=(k2%lcm+lcm)%lcm;
B=(B+ksc(ksc(k,k1,lcm),A,lcm))%lcm;
A=lcm;
}
cout<<B;
return 0;
}
莫比乌斯反演:
//给定 $N, M$,求 $1 \leq x \leq N$,$1 \leq y \leq M$ 且 $\gcd(x, y)$ 为质数的 $(x, y)$ 有多少对。
void init()
{
mu[1]=1;
for(int i=2;i<=10000000;++i)
{
if(!vis[i]) t[++top]=i,mu[i]=-1;
for(int j=1;j<=top;++j)
{
if(t[j]*i>10000000) break;
vis[t[j]*i]=true;
if(i%t[j]==0) break;
mu[t[j]*i]=-mu[i];
}
}
for(int i=1;i<=top;++i)
for(int j=1;j*t[i]<=10000000;++j)
sum[j*t[i]]+=mu[j];
for(int i=1;i<=10000000;++i)
sum[i]+=sum[i-1];
}
int main()
{
T=read(); init();
while(T--)
{
n=read(); m=read(); ans=0;
if(n>m) swap(n,m);
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(ll)(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}
//欧拉筛,mu,phi
int mu[N];
int pre[N];
int phi[N];
int t[N],top;
vector<int >P[N];
inline void init(){
mu[1]=1; phi[1]=1;
for(int i=2;i<N;i++){
if(!pre[i]) pre[i]=i,mu[i]=-1,phi[i]=i-1,t[++top]=i;
for(int j=1;j<=top&&t[j]*i<N;j++){
pre[t[j]*i]=t[j];
mu[t[j]*i]=mu[i]*(pre[i]==t[j]? 0:-1);
phi[t[j]*i]=phi[i]*(pre[i]==t[j]? t[j]:t[j]-1);
}
}
for(int i=1;i<N;++i)
for(int j=i;j<N;j+=i)
P[j].push_back(i);
}
线性基:
struct XB{
int l,r;
int a[20];
int pos[20];
XB(){
l=r=0;
memset(a,0,sizeof(a));
memset(pos,0,sizeof(pos));
}
void insert(int x,int p){
for(int i=19;i>=0;--i){
if(!(x>>i&1)) continue;
if(!a[i]){
a[i]=x;
pos[i]=p;
break;
}else{
if(p<pos[i]){
swap(a[i],x);
swap(pos[i],p);
}
x^=a[i];
}
}
}
XB(int L,int R,int A){
l=L; r=R;
memset(a,0,sizeof(a));
memset(pos,0,sizeof(pos));
insert(A,L);
}
int find(int x,int p){//查询某个数是线性基中第几大,从0开始
if(x<0) return -1;
int nw=-1;
for(int i=0;i<=19;++i)
if(a[i]&&pos[i]<=p) nw++;
int res=0; int tmp=0;
for(int i=19;i>=0;--i){
if(!a[i]||pos[i]>p) continue;
if((tmp>>i&1)==(x>>i&1)){
if(tmp>>i&1) res+=1<<nw;
}
else{
if((~tmp)>>i&1) res+=1<<nw;
tmp^=a[i];
}
nw--;
}
return res;
}
int kth(int x,int p){//查询线性基中第几大是谁,从0开始
int nw=-1;
for(int i=0;i<=19;++i)
if(a[i]&&pos[i]<=p) nw++;
if(x>=(1<<(nw+1))) return -1;
int res=0;
for(int i=19;i>=0;--i){
if(!a[i]||pos[i]>p) continue;
if(x>>nw&1) res=max(res,res^a[i]);
else res=min(res,res^a[i]);
nw--;
}
return res;
}
};

浙公网安备 33010602011771号