MD5hash(Linux)
# Hashes a cpp file, ignoring whitespace and comments.
# Usage: $ sh ./hash-cpp.sh < code.cpp
cpp -dD -P -fpreprocessed | tr -d '[:space:]' | md5sum
科学计数法
cout << setiosflags(ios::scientific) << setprecision(20);
头文件
#include<bits/stdc++.h>
#define int long long
using namespace std;
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while (0)
void err() {
cout << endl << endl;
}
template<class T, class... Ts>
void err(T arg, Ts ... args) {
cout << fixed << setprecision(10) << arg << ' ';
err(args...);
}
void solve(){
${1}
return ;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while(t--)solve();
return 0;
}
AC自动机
struct AC{
vector<vector<int>> tr;
vector<int> fail;
vector<int> cnt;
vector<int> du;
vector<int> lazy;
int tot;
AC(int n){
tr = vector<vector<int>>(26, vector<int>(n + 1));
fail.assign(n + 1, 0);
cnt.assign(n + 1, 0);
du.assign(n + 1, 0);
lazy.assign(n + 1, 0);
tot = 0;
}
void insert(string s){
int p = 0;
for(auto x : s){
int ch = x - 'a';
if(!tr[ch][p])tr[ch][p] = ++tot;
p = tr[ch][p];
}
//注意模式串是否重复
cnt[p]++;//字符串结尾标记
}
//返回字符串s匹配了几次
int get_cnt(string s){
int p = 0;
for(auto x : s){
int ch = x - 'a';
p = tr[ch][p];
}
return lazy[p];
}
void get_fail(){
queue<int>q;
for(int i = 0; i <26; i++){
if(tr[i][0])q.push(tr[i][0]);
}
while(!q.empty()){
int now = q.front();
q.pop();
for(int i = 0; i < 26; i++){
if(tr[i][now]){
fail[tr[i][now]] = tr[i][fail[now]];//连向上一层的
q.push(tr[i][now]);
}else{
tr[i][now] = tr[i][fail[now]];
}
}
}
}
/*
int query(string s){//相当于每次枚举了r然后去匹配这个后缀
int ans = 0;
int p = 0;
for(auto x : s){
int ch = x - 'a';
p = tr[ch][p];
int temp = p;
while(temp && cnt[temp] != -1){
//注意是否需要重复跑,重复跑复杂度最坏nm,传递tag,拓扑建图优化
//注意cnt为0只是说明没有以这个为后缀的字符串还需要往上跑
ans += cnt[temp];//匹配上
cnt[temp] = -1;//匹配过不再走
temp = fail[temp];
}
}
return ans;
}
*/
void run(string s){
get_fail();
for(int i = 1; i <= tot; i++){
du[fail[i]]++;
}
int p = 0;
for(auto x : s){
int ch = x - 'a';
p = tr[ch][p];
int temp = p;
lazy[temp]++;
}
queue<int> q;
for(int i = 1; i <= tot; i++){
if(!du[i])q.push(i);
}
while(!q.empty()){
int u = q.front();
q.pop();
int v = fail[u];
du[v]--;
lazy[v] += lazy[u];
if(!du[v])q.push(v);
}
return ;
}
};
PAM
struct PAM{
static constexpr int ASIZE = 26;
struct Node{
int len;
int fail;
int cnt; //以它结尾的回文子串个数
array<int, ASIZE> nex;
Node() : len(0), fail(0), cnt(0), nex{} {}
};
vector<Node> tr;
vector<int> res;
int suff;
string s;
PAM() {
init();
}
void init(){
tr.assign(2, Node());
tr[0].len = 0; //偶根
tr[0].fail = 1;
tr[1].len = -1; //奇根
tr[1].fail = 0;
suff = 0;
s.clear();
res.clear();
/*
你0、1一个是偶数空,一个是奇数空
怎么跳fail都匹配不上,但是它 会在奇数根1下面挂上,表示单独的字符C。
fail[0]=1 让0指向1,就实现了增添新的单独字符的功能。
跳fail的本质过程是判断能不能加入新的位
不能在单个字符周围加入新的字符形成长度为3的新回文串
不代表不能在“0空”位置形成 aa,bb,ccaa,bb,cc这样长度为2的回文串。
*/
}
int newNode(){
tr.emplace_back();
return tr.size() - 1;
}
int getFail(int x){
int pos = s.size() - 1;
int cur = x, curlen = 0;
while(true){
curlen = tr[cur].len;
if(pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]){
break;
}
cur = tr[cur].fail;
}
return cur;
}
bool add(char c){
s += c;
int let = c - 'a';
int cur = getFail(suff);
if(tr[cur].nex[let]){
suff = tr[cur].nex[let];
res.push_back(suff);
return false;
}
int num = newNode();
suff = num;
res.push_back(suff);
tr[num].fail = tr[getFail(tr[cur].fail)].nex[let];
tr[cur].nex[let] = num;
tr[num].len = tr[cur].len + 2;
tr[num].cnt = tr[tr[num].fail].cnt + 1;
return true;
/*
1.如果i从0开始,i−len[x]−1可能出现负数,特判一下。
2.求新点的fail时是getfail(fail[pos])如果写成了getfail(pos)自己会被当成是自己的最长回文后缀,fail指向自己会导致程序死循环。
3.求新点的fail必须在建立新点之前!
否则考虑 要建立奇数根下的点时(abbbc),他们fail[i]=0,getfail(fail[pos])会跳到1(0匹配的话不会再1下建点),如果1下已经建立它的点,fail也会指向他自己导致程序卡死
*/
}
int run(){
vector<int> f(tr.size());
for(auto v : res){
f[v]++; // 在s中的出现次数
}
vector<vector<int>> adj(tr.size());
for(int i = 2; i < tr.size(); i++){
adj[tr[i].fail].push_back(i);
}
int ans = 0;
auto dfs = [&](auto self, int x) -> void{
for(auto y : adj[x]){
self(self, y);
f[x] += f[y];
}
ans = max(ans, tr[x].len * f[x]);
};
dfs(dfs, 0);// fail只会连到偶根
// 倒序遍历就是拓扑序
// for(int i = tr.size() - 1; i >= 2; i--){
// // dbg(i, tr[i].fail);
// f[tr[i].fail] += f[i];
// }
return ans;
}
/*
时间复杂度O(n),这棵树的节点个数-2就是本质不同的回文串个数
首先建立的节点数是O(n)的
其次因为每次执行while循环的时候cur的深度会-1
而cur的深度总共增加了n次(for循环中)
所以while的执行次数也是O(n)的
*/
};
Manacher
struct Manacher{
string res;
vector<int> p;
Manacher(string s){
res = "^";
for(auto x : s){
res += '#';
res += x;
}
res += "#&";
p.resize(res.size() + 1);
run();
// s = abc idx 0 1 2
// res = ^#a#b#c#& idx 2 4 6
// s_idx -> res_idx * 2 + 2
}
void run(){
int len = res.size();
int c = 0, r = 0;
for(int i = 1; i < len; i++){
if(i <= r){
p[i] = min(p[2 * c - i], r - i);
}
while(res[i - p[i] - 1] == res[i + p[i] + 1])p[i]++;
if(i + p[i] > r){
c = i;
r = i + p[i];
}
}
return ;
}
pair<int, int> get(){
int start = max_element(p.begin(), p.end()) - p.begin();
int max_len = p[start];
return {start, max_len};
// (i - p[i]) / 2是回文起始点,字符串下标从0开始
// s_li = (i - p[i] + 1) / 2 - 1
// s_ri = (i + p[i]) / 2 - 1
}
bool check(int l, int r){
int len = (r - l + 1);
int center = (l + r) / 2;
center = center * 2 + 2;
if(len % 2 == 0)center++;
return p[center] >= len;
}
};
矩阵快速幂
template <class T, const int M>
struct Matrix{
T m[M][M];
int row, col;
Matrix(){
row = 0;
col = 0;
}
Matrix(int n){ //单位矩阵
row = col = n;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i == j)m[i][j] = 1;
else m[i][j] = 0;
}
}
}
Matrix(int r, int c){
row = r;
col = c;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
m[i][j] = 0;
}
}
}
Matrix(vector<vector<T>> a){
row = a.size();
col = a[0].size();
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
m[i][j] = a[i][j];
}
}
}
Matrix operator * (const Matrix &y) const {
Matrix res(row, y.col);
for(int i = 0; i < row; i++){
for(int j = 0; j < y.col; j++){
for(int k = 0; k < col; k++){
res.m[i][j] += m[i][k] * y.m[k][j];
}
}
}
return res;
}
Matrix qmi (long long b){
Matrix res(row);
Matrix a = *this;
while(b){
if(b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
friend ostream &operator<<(ostream &os, const Matrix &a) {
for(int i = 0; i < a.row; i++){
for(int j = 0; j < a.col; j++){
os << a.m[i][j] << ' ';
}
os << '\n';
}
return os;
}
};
using matrix = Matrix<$1>;
广义矩阵(max + )
constexpr int inf = 1e9;
template <class T, const int M>
struct Matrix{
T m[M][M];
int row, col;
Matrix(){
row = 0;
col = 0;
}
Matrix(int n){ //单位矩阵
row = col = n;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i == j)m[i][j] = 0;
else m[i][j] = -inf;
}
}
}
Matrix(int r, int c){
row = r;
col = c;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
m[i][j] = -inf;
}
}
}
Matrix(vector<vector<T>> a){
row = a.size();
col = a[0].size();
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
m[i][j] = a[i][j];
}
}
}
Matrix operator * (const Matrix &y) const {
Matrix res(row, y.col);
for(int i = 0; i < row; i++){
for(int j = 0; j < y.col; j++){
for(int k = 0; k < col; k++){
res.m[i][j] = max(res.m[i][j], m[i][k] + y.m[k][j]);
}
}
}
return res;
}
Matrix qmi (long long b){
Matrix res(row);
Matrix a = *this;
while(b){
if(b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
friend ostream &operator<<(ostream &os, const Matrix &a) {
for(int i = 0; i < a.row; i++){
for(int j = 0; j < a.col; j++){
os << a.m[i][j] << ' ';
}
os << '\n';
}
return os;
}
};
using matrix = Matrix<>;
最大流
- 二分图
struct Max_Flow{
//#define int long long
static constexpr int inf = 1e18;
struct node{
int v, w;
};
int n;
vector<node> e;
vector<vector<int>> g;
vector<int> h, cur;
Max_Flow(int n){
init(n);
}
void add(int u, int v, int w){
g[u].push_back(e.size());
e.push_back({v, w});
g[v].push_back(e.size());
e.push_back({u, 0});
}
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);
queue<int> q;
h[s]=0;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
for(auto i : g[u]){
auto [v, w] = e[i];
if(h[v] == -1 && w){
h[v] = h[u] + 1;
if(v == t){
return true;
}
q.push(v);
}
}
}
return false;
}
int dfs(int u, int t, int val){
if(u == t)return val;
int res = val;
for(auto &i = cur[u]; i < (int)g[u].size(); i++){
int j = g[u][i];
auto [v, w] = e[j];
if(w > 0 && h[v] == h[u] + 1){
int d = dfs(v, t, min(res, w));
e[j].w -= d;
e[j ^ 1].w += d;
res -= d;
if(res == 0)return val;
}
}
return val - res;
}
int flow(int s, int t){
int ans = 0;
while(bfs(s, t)){
cur.assign(n, 0);
ans += dfs(s, t, inf);
}
return ans;
}
vector<int> mincut(){
vector<int> res;
for(int i = 0; i < n; i++){
if(h[i] != -1)res.push_back(i);
}
return res;
}
vector<int> get_mincut_edge(){
vector<int> res;
for(int i = 0; i < e.size(); i += 2){
int u = e[i + 1].v;
int v = e[i].v;
if(h[u] != -1 && h[v] == -1){
res.push_back(u);
}
}
return res;
}
};
最小费用最大流
- 原始对偶算法实现
struct MCFGraph {
//#define int long long
static constexpr int inf = 1e18;
struct Edge {
int v, c, f;
Edge(int v, int c, int f) : v(v), c(c), f(f) {}
};
const int n;
vector<Edge> e;
vector<vector<int>> g;
vector<int> h, dis;
vector<int> pre;
bool dijkstra(int s, int t) {
dis.assign(n, inf);
pre.assign(n, -1);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, 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]) {
auto[v, c, f] = e[i];
if (c > 0 && dis[v] > d + h[u] - h[v] + f) {
dis[v] = d + h[u] - h[v] + f;
pre[v] = i;
que.emplace(dis[v], v);
}
}
}
return dis[t] != inf;
}
MCFGraph(int n) : n(n), g(n) {}
void addEdge(int u, int v, int c, int f) {
g[u].push_back(e.size());
e.emplace_back(v, c, f);
g[v].push_back(e.size());
e.emplace_back(u, 0, -f);
}
pair<int, int> flow(int s, int t) {
int flow = 0;
int cost = 0;
h.assign(n, 0);
while (dijkstra(s, t)) {
for (int i = 0; i < n; ++i) h[i] += dis[i];
int aug = inf;
for (int i = t; i != s; i = e[pre[i] ^ 1].v) aug = min(aug, e[pre[i]].c);
for (int i = t; i != s; i = e[pre[i] ^ 1].v) {
e[pre[i]].c -= aug;
e[pre[i] ^ 1].c += aug;
}
flow += aug;
cost += aug * h[t];
}
return {flow, cost};
}
};
- O
- 基于dinic实现
struct MCFGraph{
//#define int long long
static constexpr int inf = 1e18;
struct Edge {
int v, c, f;
Edge(int v, int c, int f) : v(v), c(c), f(f) {}
};
int n;
vector<Edge> e;
vector<vector<int>> g;
vector<int> dis, cur, vis;
MCFGraph(int n){
this->n = n;
e.clear();
g.assign(n, {});
cur.assign(n, 0);
vis.assign(n, 0);
}
void add(int u, int v, int c, int f){
g[u].push_back(e.size());
e.emplace_back(v, c, f);
g[v].push_back(e.size());
e.emplace_back(u, 0, -f);
}
bool bfs(int s, int t){
dis.assign(n, inf);
queue<int> que;
dis[s] = 0;
vis[s] = 1;
que.push(s);
while(!que.empty()){
int u = que.front();
que.pop();
vis[u] = 0;
for(auto i : g[u]){
auto [v, c, f] = e[i];
if(c > 0 && dis[v] > dis[u] + f){
dis[v] = dis[u] + f;
if(!vis[v]){
vis[v] = 1;
que.push(v);
}
}
}
}
return dis[t] != inf;
}
int dfs(int u, int t, int flow){
if (u == t) return flow;
vis[u] = 1;
int used = 0;
for(int &i = cur[u]; i < (int)g[u].size(); i++){
int j = g[u][i];
auto [v, c, f] = e[j];
if(!vis[v] && c > 0 && dis[v] == dis[u] + f){
int k = dfs(v, t, min(flow - used, c));
used += k;
e[j].c -= k;
e[j ^ 1].c += k;
if(used == flow) break;
}
}
vis[u] = 0;
return used;
}
pair<int, int> flow(int s, int t){
int flow = 0;
int cost = 0;
while(bfs(s, t)){
cur.assign(n, 0);
int aug = dfs(s, t, inf);
flow += aug;
cost += dis[t] * aug;
}
return {flow, cost};
}
};
可撤销并查集
vector<int> f(n + 1), sz(n + 1);
vector<int>stk;
for(int i = 1; i <= n; i++)f[i] = i, sz[i] = 1;
auto find = [&](int x) -> int{
while(f[x] != x){
x = f[x];
}
return x;
};
auto merge = [&](int x) -> void{
auto [a, b] = edge[x];
int fa = find(a);
int fb = find(b);
if(fa == fb)return ;
if(sz[fa] > sz[fb])swap(fa, fb);
f[fa] = fb;
sz[fb] += sz[fa];
stk.push_back(fa);
};
auto rollback = [&](int x) -> void{
while(stk.size() > x){
int fa = stk.back();
int fb = f[fa];
stk.pop_back();
f[fa] = fa;
sz[fb] -= sz[fa];
}
};
自动取模类
- 注意 /0 * 0,要计数处理
template<const int T>
struct ModInt {
const static int mod = T;
int x;
ModInt(int x = 0) : x(x < 0 ? x % mod + mod : x % mod) {}
ModInt(long long x) : x(int(x < 0 ? x % mod + mod : x % mod)) {}
int val() { return x; }
ModInt operator + (const ModInt &a) const {
int x0 = x + a.x;
return ModInt(x0 < mod ? x0 : x0 - mod);
}
ModInt operator - (const ModInt &a) const {
int x0 = x - a.x;
return ModInt(x0 < 0 ? x0 + mod : x0);
}
ModInt operator * (const ModInt &a) const {
return ModInt(1LL * x * a.x % mod);
}
ModInt operator / (const ModInt &a) const {
return *this * a.inv();
}
bool operator == (const ModInt &a) const {
return x == a.x;
}
bool operator != (const ModInt &a) const {
return x != a.x;
}
void operator += (const ModInt &a) {
x += a.x;
if (x >= mod) x -= mod;
}
void operator -= (const ModInt &a) {
x -= a.x;
if (x < 0) x += mod;
}
void operator *= (const ModInt &a) {
x = 1LL * x * a.x % mod;
}
void operator /= (const ModInt &a) {
*this = *this / a;
}
friend ModInt operator + (int y, const ModInt &a){
int x0 = y + a.x;
return ModInt(x0 < mod ? x0 : x0 - mod);
}
friend ModInt operator - (int y, const ModInt &a){
int x0 = y - a.x;
return ModInt(x0 < 0 ? x0 + mod : x0);
}
friend ModInt operator * (int y, const ModInt &a){
return ModInt(1LL * y * a.x % mod);
}
friend ModInt operator / (int y, const ModInt &a){
return ModInt(y) / a;
}
friend ostream &operator<<(ostream &os, const ModInt &a) {
return os << a.x;
}
friend istream &operator>>(istream &is, ModInt &t){
return is >> t.x;
}
ModInt pow(long long n) const {
ModInt res(1), mul(x);
while(n){
if (n & 1) res *= mul;
mul *= mul;
n >>= 1;
}
return res;
}
ModInt inv() const {
int a = x, b = mod, u = 1, v = 0;
while (b) {
int t = a / b;
a -= t * b; swap(a, b);
u -= t * v; swap(u, v);
}
if (u < 0) u += mod;
return u;
}
};
constexpr int mod = $1;
using mint = ModInt<mod>;
lca
vector<int> dep(n + 1);
vector<vector<int>> f(25, vector<int>(n + 1));
auto dfs = [&](auto self, int now, int father) -> void{
dep[now] = dep[father]+1;
f[0][now] = father;
for(int i = 1; i <= 20; i++){
f[i][now] = f[i - 1][f[i - 1][now]];
}
for(auto v : g[now]){
if(v == father)continue;
self(self, v, now);
}
return ;
};
dfs(dfs, 1, 0);
auto lca = [&](int a, int b) -> int{
if(dep[a] < dep[b])swap(a,b);
for(int i = 20; i >= 0; i--){
if(dep[a] - (1ll << i) >= dep[b])a = f[i][a];
}
if(a == b)return a;
for(int i = 20; i >= 0; i--){
if(f[i][a] != f[i][b]){
a = f[i][a];
b = f[i][b];
}
}
return f[0][a];
};
dfn序求lca O(1)
vector<int>dfn(n + 1), dep(n + 1);
vector st(21, vector<pair<int, int>>(n + 1));
int tot = 0;
auto dfs = [&](auto self, int now, int father) -> void{
dfn[now] = ++tot;
dep[now] = dep[father] + 1;
st[0][tot] = {dep[now], father};
for(auto v : g[now]){
if(v == father)continue;
self(self, v, now);
}
};
dfs(dfs, 1, 0);
for(int k = 1; k <= 20; k++){
for(int i = 1; i + (1ll << k) <= n + 1; i++){
st[k][i] = min(st[k - 1][i], st[k - 1][i + (1ll << (k - 1))]);
}
}
auto lca = [&](int a, int b) -> int{
if(a == b)return a;
if(dfn[a] > dfn[b])swap(a, b);
int l = dfn[a] + 1;
int r = dfn[b];
int len = (r - l + 1);
int d = __lg(len);
return min(st[d][l], st[d][r - (1ll << d) + 1]).second;
};
cdq分治
auto cdq = [&](auto self, int l, int r) -> void{
if(l == r)return ;
int mid = (l + r) >> 1;
self(self, l, mid);
self(self, mid + 1, r);
int i = l, j = mid + 1;
for(; j <= r; j++){
while(i <= mid && q[j].b > q[i].b){
add(q[i].c, 1);
i++;
}
du[q[j].a] += ask(q[j].c - 1);
}
for(i--; i >= l; i--){
add(q[i].c, -1);
}
sort(q.begin() + l, q.begin() + r + 1, cmp);//第二关键字排序
};
cdq(cdq, 1, n);
整体二分
struct Num {
int x, y, val;
};
struct node{
int x1, y1, x2, y2, k, id;
};
void solve(){
int n, q; cin >> n >> q;
vector a(n + 1, vector<int>(n + 1));
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++) cin >> a[i][j];
}
vector tr(n + 1, vector<int>(n + 1));
auto add = [&](int x, int y, int d)->void{
for (int i = x; i <= n; i += lowbit(i)) {
for (int j = y; j <= n; j += lowbit(j)) {
tr[i][j] += d;
}
}
};
auto ask = [&](int x, int y)->int{
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -=lowbit(j)) {
res += tr[i][j];
}
}
return res;
};
vector<node>Q;
vector<int>ans(q + 1);
for(int i = 1;i <= q; i++){
int x1, y1, x2, y2, k;cin >> x1 >> y1 >> x2 >> y2 >>k;
Q.push_back({x1, y1, x2, y2, k, i});
}
vector<Num>temp;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
temp.push_back({i, j, a[i][j]});
}
}
auto fz = [&](auto self,int l,int r,vector<Num>b,vector<node>QQ)->void{
if(l == r){
for(auto [x1, y1, x2, y2, k, id] : QQ){
//dbg(id);
ans[id] = l;
}
return ;
}
if(QQ.empty())return ;
int mid = (l + r) >> 1;
vector<Num> a1, a2;
vector<node> q1, q2;
for(auto [x, y, val] : b){
if(val <= mid){
a1.push_back({x, y, val});
add(x, y, 1);
}else a2.push_back({x, y, val});
}
for(auto [x1, y1, x2, y2, k, id] : QQ){
int d=ask(x2, y2) + ask(x1 - 1, y1 - 1) - ask(x1 - 1,y2) - ask(x2, y1 - 1);
if(k <= d){
q1.push_back({x1, y1, x2, y2, k, id});
}else{
q2.push_back({x1, y1, x2, y2, k - d, id});
}
}
for(auto [x,y,val]:b){
if(val<=mid){
add(x,y,-1);
}
}
self(self,l,mid,a1,q1);
self(self,mid+1,r,a2,q2);
};
fz(fz,0,1e9,temp,Q);
for(int i=1;i<=q;i++)cout<<ans[i]<<'\n';
return ;
}
数位dp
auto get = [&](int x)->int{
vector dp(10,vector(10,vector(2,vector<int>(2))));
vector<int>p;
int temp=x;
while(temp){
p.push_back(temp%10);
temp/=10;
}
auto dfs = [&](auto self,int now,int last,int limit,int lead)->int{
if(now==-1)return 1;
if(dp[now][last][limit][lead]!=0)return dp[now][last][limit][lead];
int res=0;
for(int i=0;i<=(limit?p[now]:9);i++){
if(lead==1)res+=self(self,now-1,i,limit&&i==p[now],i==0);
else{
if(abs(i-last)>=2)res+=self(self,now-1,i,limit&&i==p[now],0);
}
}
return dp[now][last][limit][lead]=res;
};
return dfs(dfs,p.size()-1,0,1,1);
};
01trie
struct trie{
struct node{
int l, r;
};
int tot;
vector<node>tr;
vector<array<int, 2>> tag;
int Max = (1ll << 31) - 1;
trie(int n){
tot = 1;
tr.assign(n, {0, 0});
tag.assign(n, {0, 0});
}
void cg(int p, array<int, 2> val){
tag[p][0] |= val[0];
tag[p][1] -= tag[p][1] & val[0];
tag[p][1] ^= val[1];
}
void down(int p, int dep){
if((tag[p][0] >> dep) & 1){
merge(tr[p].r, tr[p].l, dep - 1);
}
if((tag[p][1] >> dep) & 1){
swap(tr[p].l, tr[p].r);
}
if(tr[p].l)cg(tr[p].l, tag[p]);
if(tr[p].r)cg(tr[p].r, tag[p]);
tag[p] = {0, 0};
}
void merge(int &x, int &y, int dep){ // x <- y
if(!y || !x){
x = x | y;
y = 0;
return ;
}
if(dep == -1){
y = 0;
return ;
}
down(x, dep);down(y, dep);
merge(tr[x].l, tr[y].l, dep - 1);
merge(tr[x].r, tr[y].r, dep - 1);
y = 0;
return ;
}
void insert(int x){
int p = 1;
for(int i = 30; i >= 0; i--){
int d = (x >> i) & 1;
down(p, i);
if(d == 0){
if(!tr[p].l)tr[p].l = ++tot;
p = tr[p].l;
}else{
if(!tr[p].r)tr[p].r = ++tot;
p = tr[p].r;
}
}
}
int query(int x){
int res = 0;
int p = 1;
for(int i = 30; i >= 0; i--){
down(p, i);
int d = (x >> i) & 1;
d = 1 ^ d;
if(d == 0){
if(tr[p].l){
res += 1ll << i;
p = tr[p].l;
}else{
p = tr[p].r;
}
}else{
if(tr[p].r){
res += 1ll << i;
p = tr[p].r;
}else{
p = tr[p].l;
}
}
}
return res;
}
};
线段树合并
- 注意合并的时候考虑贡献要是未覆盖
- 只要需要考虑根节点的合并即可
- 复杂度证明,每次复杂度是重复节点个数,也是相当于删除重复节点,所以总复杂度
auto merge = [&](auto self, int l, int r, int x, int y) -> int{
if(!x || !y)return x | y;
int mid = (l + r) >> 1;
int rt = ++tot;
if(l == r){
tr[rt].val = l;
tr[rt].cnt = tr[x].cnt + tr[y].cnt;
return rt;
}
tr[rt].l = self(self, l, mid, tr[x].l, tr[y].l);
tr[rt].r = self(self, mid + 1, r, tr[x].r, tr[y].r);
up(rt);
return rt;
};
auto dfs2 = [&](auto self, int now, int father) -> void{
for(auto v : g[now]){
if(v == father)continue;
self(self, v, now);
root[now] = merge(merge, 1, 1e5, root[v], root[now]);
}
};
//引用版
auto merge = [&](auto self, int l, int r, int &x, int y) -> void{
if(!x || !y){
x = x | y;
return ;
}
if(l == r){
tr[x].val += tr[y].val;
return ;
}
int mid = (l + r) >> 1;
tr[x].val += tr[y].val;
self(self, l, mid, tr[x].l, tr[y].l);
self(self, mid + 1, r, tr[x].r, tr[y].r);
};
//拿到父亲那边的子树情况
auto run = [&](auto self, int l, int r, int x, int y) -> void{
if(tr[x].cnt - tr[y].cnt == 0)return ;
if(tr[y].cnt == 0)return ;
int mid = (l + r) >> 1;
if(l == r){
int d = tr[x].cnt - tr[y].cnt;
return ;
}
self(self, l, mid, tr[x].l, tr[y].l, f);
self(self, mid + 1, r, tr[x].r, tr[y].r, f);
return ;
};
auto dfs2 = [&](auto self, int now, int father) -> void{
for(auto v : g[now]){
if(v == father)continue;
run(run, 1, n, root[1], root[v]);
self(self, v, now);
}
};
线段树合并示例(维护链信息)
constexpr long long Max = 1e18;
struct node{
int l, r;
long long val, tag;
};
void solve(){
int n; cin >> n;
vector<int> c(n + 1), w(n + 1);
for(int i = 1; i <= n; i++) cin >> c[i];
for(int i = 1; i <= n; i++) cin >> w[i];
vector<vector<int>>g(n + 1);
for(int i = 1; i < n; i++){
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> root(n + 1);
vector<long long> dp(n + 1);
vector<node> tr(n * 40);
int tot = 0;
long long sum = 0;
auto cg = [&](int p, long long val) -> void{
tr[p].val += val;
tr[p].tag += val;
};
auto down = [&](int p) -> void{
if(tr[p].tag != 0){
int ls = tr[p].l;
int rs = tr[p].r;
if(ls)cg(ls, tr[p].tag);
if(rs)cg(rs, tr[p].tag);
tr[p].tag = 0;
}
};
auto updata = [&](auto self, int l, int r, int x, int val, int &p) -> void{
if(!p)p = ++tot;
tr[p].val = val;
if(l == r)return ;
int mid = (l + r) >> 1;
if(x <= mid)self(self, l, mid, x, val, tr[p].l);
else self(self, mid + 1, r, x, val, tr[p].r);
};
auto merge = [&](auto self, int l, int r, int &x, int y, long long &res) -> void{
if(!x || !y){
x = x | y;
return ;
}
if(l == r){
res = max(res, tr[x].val + tr[y].val + sum);
tr[x].val = max(tr[x].val, tr[y].val);
return ;
}
down(x);down(y);
tr[x].val = max(tr[x].val, tr[y].val);
int mid = (l + r) >> 1;
self(self, l, mid, tr[x].l, tr[y].l, res);
self(self, mid + 1, r, tr[x].r, tr[y].r, res);
return ;
};
auto dfs2 = [&](auto self, int now, int father) -> void{
sum = 0;
long long sm = 0;
for(auto v : g[now]){
if(v == father)continue;
self(self, v, now);
sm += dp[v];
}
sum = sm;
dp[now] = sum;
updata(updata, 1, n, c[now], w[now], root[now]);
for(auto v : g[now]){
if(v == father)continue;
cg(root[v], -dp[v]);
merge(merge, 1, n, root[now], root[v], dp[now]);
}
cg(root[now], sm);//先减后加刚刚好是向上延申一个节点的价值
};
dfs2(dfs2, 1, 0);
cout << dp[1] << '\n';
return ;
}
线段树分裂
- 一般与线段树合并一起使用,可以分裂出一个新的集合,然后合并回来
auto split = [&](auto self, int l, int r, int x, int y, int &u, int &v) -> void{
if(x <= l && r <= y){
v = u;
u = 0;
return ;
}
v = ++tot;
int mid = (l + r) >> 1;
if(x <= mid)self(self, l, mid, x, y, tr[u].lson, tr[v].lson);
if(y > mid)self(self, mid + 1, r, x, y, tr[u].rson, tr[v].rson);
up(u);
up(v);
};
线段树优化建图
void solve(){
int n,m,p;cin>>n>>m>>p;
vector<int>ps(n+1);
vector g(8*n+2*m+1,vector<pair<int,int>>());
int pdx=4*n;// > pdx 是出树
//可以根据连点是否都是区间来判断要建几个树
auto bulid = [&](auto self,int l,int r,int p)->void{
if(p!=1)g[p + pdx].push_back({p / 2 + pdx,0});
if(l == r){
ps[l] = p;
g[p+pdx].push_back({p,0});
g[p].push_back({p+pdx,0});
return ;
}
int mid=(l+r)>>1;
g[p].push_back({p<<1,0});
g[p].push_back({p<<1|1,0});
self(self,l,mid,p<<1);
self(self,mid+1,r,p<<1|1);
};
bulid(bulid,1,n,1);
auto link = [&](auto self,int l,int r,int x,int y,int k,int t,int p)->void{
if(x<=l&&r<=y){
if(t==1){
g[k].push_back({p,1});
g[p+pdx].push_back({k+1,1});// 出边从出树连出
}else{
g[k+1].push_back({p,1});
g[p+pdx].push_back({k,1});
}
return ;
}
int mid=(l+r)>>1;
if(x<=mid)self(self,l,mid,x,y,k,t,p<<1);
if(y>mid)self(self,mid+1,r,x,y,k,t,p<<1|1);
};
for(int i=1;i<=m;i++){
int a,b,c,d;cin>>a>>b>>c>>d;
// a,b 连向 c, d 双向
link(link,1,n,a,b,2*i-1+2*pdx,1,1);
link(link,1,n,c,d,2*i-1+2*pdx,2,1);
}
vector<int>d(8*n+2*m+1,INT_MAX);
auto dijkstra = [&]()->void{
vector<int>vis(8*n+2*m+1);
p=ps[p]+pdx;
d[p]=0;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
q.push({0,p});
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:g[u]){
if(d[v]>d[u]+w){
d[v]=d[u]+w;
q.push({d[v],v});
}
}
}
};
dijkstra();
for(int i=1;i<=n;i++){
cout<<d[ps[i]+pdx]/2<<'\n';
}
return ;
}
线段树分治
constexpr int maxn = 2e5 + 5;
void solve(){
int n, m; cin >> n >> m;
vector<int> l(n + 1), r(n + 1);
for(int i = 1; i <= n; i++){
cin >> l[i] >> r[i];
}
vector<pair<int, int>>edge;
vector<int> f(n + 1), sz(n + 1), ans(n + 1);
vector<int>stk;
for(int i = 1; i <= n; i++)f[i] = i, sz[i] = 1;
auto find = [&](int x) -> int{
while(f[x] != x){
x = f[x];
}
return x;
};
auto merge = [&](int x) -> void{
auto [a, b] = edge[x];
int fa = find(a);
int fb = find(b);
if(fa == fb)return ;
if(sz[fa] > sz[fb])swap(fa, fb);
f[fa] = fb;
sz[fb] += sz[fa];
ans[fa] -= ans[fb];
stk.push_back(fa);
};
auto rollback = [&](int x) -> void{
while(stk.size() > x){
int fa = stk.back();
int fb = f[fa];
stk.pop_back();
f[fa] = fa;
sz[fb] -= sz[fa];
ans[fa] += ans[fb];
}
};
vector<vector<int>> tr(maxn * 4);
auto updata = [&](auto self, int l, int r, int x, int y, int val, int p) -> void{
if(x <= l && r <= y){
tr[p].push_back(val);
return ;
}
int mid = (l + r) >> 1;
if(x <= mid)self(self, l, mid, x, y, val, p << 1);
if(y > mid)self(self, mid + 1, r, x, y, val, p << 1 | 1);
};
auto dfs = [&](auto self, int l, int r, int p) -> void{
int sz = stk.size();
for(auto x : tr[p])merge(x);
if(l == r){
ans[find(1)]++;
rollback(sz);
return ;
}
int mid = (l + r) >> 1;
self(self, l, mid, p << 1);
self(self, mid + 1, r, p << 1 | 1);
rollback(sz);
};
for(int i = 1; i <= m; i++){
int u, v; cin >> u >> v;
int ll = max(l[u], l[v]);
int rr = min(r[u], r[v]);
if(ll <= rr){
updata(updata, 1, maxn, ll, rr, edge.size(), 1);
edge.push_back({u, v});
}
}
dfs(dfs, 1, maxn, 1);
for(int i = 1; i <= n; i++){
if(ans[i])cout << i << ' ';
}
cout << '\n';
return ;
}
可持久化01字典树区间异或第k大
void solve(){
int n,m;cin>>n>>m;
vector<int>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
a[i]^=a[i-1];
}
vector t(2,vector<int>((n+1)*35));
vector<int>val((n+1)*35);
int tot=0;
auto ins = [&](int u,int v,int x)->void{
for(int i=31;i>=0;i--){
t[0][u]=t[0][v];
t[1][u]=t[1][v];
int d=x>>i&1;
t[d][u]=++tot;
u=t[d][u];
v=t[d][v];
val[u]=val[v]+1;
}
};
auto ask = [&](int u,int x,int k)->int{
int res=0;
for(int i=31;i>=0;i--){
int d=x>>i&1;
d^=1;
int sz=val[t[d][u]];
if(sz>=k){
res+=1ll<<i;
}else{
k-=sz;
d^=1;
}
u=t[d][u];
}
return res;
};
vector<int>root(n+1);
root[0]=++tot;
ins(root[0],0,0);
priority_queue<node>q;
int ans=0;
for(int i=1;i<=n;i++){
root[i]=++tot;
ins(root[i],root[i-1],a[i]);
}
for(int i=1;i<=n;i++){
q.push({ask(root[i],a[i],1),i,1});
}
for(int i=1;i<=m;i++){
int res=q.top().val;
int id=q.top().id;
int rk=q.top().rk;
q.pop();
ans+=res;
if(rk==n)continue;
q.push({ask(root[id],a[id],rk+1),id,rk+1});
}
cout<<ans<<'\n';
return ;
}
可持久化线段树 区间第k小
struct node{
int l,r,sum;
};
void solve(){
int n,m;cin>>n>>m;
vector<int>a(n+1);
vector<int>p;
for(int i=1;i<=n;i++)cin>>a[i],p.push_back(a[i]);
sort(p.begin(),p.end());
p.erase(unique(p.begin(),p.end()),p.end());
auto get = [&](int x)->int{
return lower_bound(p.begin(),p.end(),x)-p.begin()+1;
};
vector<node>tr(n<<5);
vector<int>root(n+1);
int tot=0;
auto bulid = [&](auto self,int &u,int l,int r)->void{
u=++tot;
if(l==r)return ;
int mid=(l+r)>>1;
self(self,tr[u].l,l,mid);
self(self,tr[u].r,mid+1,r);
return ;
};
auto updata = [&](auto self,int &u,int v,int l,int r,int x)->void{
u=++tot;
tr[u]=tr[v];
tr[u].sum++;
if(l==r)return ;
int mid=(l+r)>>1;
if(x<=mid)self(self,tr[u].l,tr[v].l,l,mid,x);
else self(self,tr[u].r,tr[v].r,mid+1,r,x);
};
auto query = [&](auto self,int u,int v,int l,int r,int k)->int{
if(l==r)return l;
int mid=(l+r)>>1;
int d=tr[tr[u].l].sum-tr[tr[v].l].sum;
if(d>=k)return self(self,tr[u].l,tr[v].l,l,mid,k);
else return self(self,tr[u].r,tr[v].r,mid+1,r,k-d);
};
bulid(bulid,root[0],1,n);
for(int i=1;i<=n;i++){
int d=get(a[i]);
updata(updata,root[i],root[i-1],1,n,d);
}
for(int i=1;i<=m;i++){
int l,r,k;cin>>l>>r>>k;
int d=query(query,root[r],root[l-1],1,n,k);
cout<<p[d-1]<<'\n';
}
return ;
}
懒标记线段树
template<class Info, class Tag>
struct LazySegmentTree{
int n;
vector<Info> info;
vector<Tag> tag;
LazySegmentTree() : n(0) {}
LazySegmentTree(int n_, Info v_ = Info()){
init(n_, v_);
}
template<class T>
LazySegmentTree(vector<T> init_){ //注意下标从1开始也就是[0] 是空
init(init_);
}
void init(int n_, Info v_ = Info()){
init(vector(n_ + 1, v_));
}
template<class T>
void init(vector<T> init_){
n = init_.size() - 1;
info.assign(n * 4, Info());
tag.assign(n * 4, Tag());
auto bulid = [&](auto self, int l, int r, int p) -> void{
if(l == r){
info[p] = init_[l];
return ;
}
int mid = (l + r) >> 1;
self(self, l, mid, p << 1);
self(self, mid + 1, r, p << 1 | 1);
up(p);
};
bulid(bulid, 1, n, 1);
}
void cg(int p, const Tag &v){
info[p].apply(v);
tag[p].apply(v);
}
void up (int p){
info[p] = info[p << 1] + info[p << 1 | 1];
}
void down (int p){
cg(p << 1, tag[p]);
cg(p << 1 | 1, tag[p]);
tag[p] = Tag();
}
void update(int l, int r, int x, const Info &v, int p){
if(l == r){
info[p] = v;
return ;
}
down(p);
int mid = (l + r) >> 1;
if(x <= mid)update(l, mid, x, v, p << 1);
else update(mid + 1, r, x, v, p << 1 | 1);
up(p);
}
void update(int x, const Info &v){
update(1, n, x, v, 1);
}
Info rangeQuery(int l, int r, int x, int y, int p){
if(x <= l && r <= y)return info[p];
Info res = Info();
down(p);
int mid = (l + r) >> 1;
if(x <= mid)res = res + rangeQuery(l, mid, x, y, p << 1);
if(y > mid)res = res + rangeQuery(mid + 1, r, x, y, p << 1 | 1);
return res;
}
Info rangeQuery(int l, int r){
return rangeQuery(1, n, l, r, 1);
}
void rangeUpdate(int l, int r, int x, int y, const Tag &val, int p){
if(x <= l && r <= y){
cg(p, val);
return ;
}
down(p);
int mid = (l + r) >> 1;
if(x <= mid)rangeUpdate(l, mid, x, y, val, p << 1);
if(y > mid)rangeUpdate(mid + 1, r, x, y, val, p << 1 | 1);
up(p);
}
void rangeUpdate(int l, int r, const Tag &val){
rangeUpdate(1, n, l, r, val, 1);
}
template<class F>
int findFirst(int l, int r, int x, int y, int p, F &&check){
if(x <= l && r <= y){
if(!check(info[p]))return -1;
if(l == r)return l;
}
down(p);
int mid = (l + r) >> 1;
if(x <= mid){
int res = findFirst(l, mid, x, y, p << 1, check);
if(res != -1)return res;
}
if(y > mid)return findFirst(mid + 1, r, x, y, p << 1 | 1, check);
return -1;
}
template<class F>
int findFirst(int l, int r, F &&check){
return findFirst(1, n, l, r, 1, check);
}
template<class F>
int findLast(int l, int r, int x, int y, int p, F &&check){
if(x <= l && r <= y){
if(!check(info[p]))return -1;
if(l == r)return l;
}
down(p);
int mid = (l + r) >> 1;
if(y > mid){
int res = findLast(mid + 1, r, x, y, p << 1 | 1, check);
if(res != -1)return res;
}
if(x <= mid)return findLast(l, mid, x, y, p << 1, check);
return -1;
}
template<class F>
int findLast(int l, int r, F &&check){
return findLast(1, n, l, r, 1, check);
}
};
struct Tag{
void apply(Tag t){
}
};
struct Info{
void apply(Tag t){
}
};
Info operator+ (const Info &a, const Info &b){
Info res = Info();
return res;
}
线段树
template<class Info>
struct SegmentTree{
int n;
vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()){
init(n_, v_);
}
template<class T>
SegmentTree(vector<T> init_){ //注意下标从1开始也就是[0] 是空
init(init_);
}
void init(int n_, Info v_ = Info()){
init(vector(n_ + 1, v_));
}
template<class T>
void init(vector<T> init_){
n = init_.size() - 1;
info.assign(n * 4, Info());
auto bulid = [&](auto self, int l, int r, int p) -> void{
if(l == r){
info[p] = init_[l];
return ;
}
int mid = (l + r) >> 1;
self(self, l, mid, p << 1);
self(self, mid + 1, r, p << 1 | 1);
up(p);
};
bulid(bulid, 1, n, 1);
}
void up (int p){
info[p] = info[p << 1] + info[p << 1 | 1];
}
void update(int l, int r, int x, const Info &v, int p){
if(l == r){
info[p] = v;
return ;
}
int mid = (l + r) >> 1;
if(x <= mid)update(l, mid, x, v, p << 1);
else update(mid + 1, r, x, v, p << 1 | 1);
up(p);
}
void update(int x, const Info &v){
update(1, n, x, v, 1);
}
Info rangeQuery(int l, int r, int x, int y, int p){
if(x <= l && r <= y)return info[p];
Info res = Info();
int mid = (l + r) >> 1;
if(x <= mid)res = res + rangeQuery(l, mid, x, y, p << 1);
if(y > mid)res = res + rangeQuery(mid + 1, r, x, y, p << 1 | 1);
return res;
}
Info rangeQuery(int l, int r){
return rangeQuery(1, n, l, r, 1);
}
template<class F>
int findFirst(int l, int r, int x, int y, int p, F &&check){
if(x <= l && r <= y){
if(!check(info[p]))return -1;
if(l == r)return l;
}
int mid = (l + r) >> 1;
if(x <= mid){
int res = findFirst(l, mid, x, y, p << 1, check);
if(res != -1)return res;
}
if(y > mid)return findFirst(mid + 1, r, x, y, p << 1 | 1, check);
return -1;
}
template<class F>
int findFirst(int l, int r, F &&check){
return findFirst(1, n, l, r, 1, check);
}
template<class F>
int findLast(int l, int r, int x, int y, int p, F &&check){
if(x <= l && r <= y){
if(!check(info[p]))return -1;
if(l == r)return l;
}
int mid = (l + r) >> 1;
if(y > mid){
int res = findLast(mid + 1, r, x, y, p << 1 | 1, check);
if(res != -1)return res;
}
if(x <= mid)return findLast(l, mid, x, y, p << 1, check);
return -1;
}
template<class F>
int findLast(int l, int r, F &&check){
return findLast(1, n, l, r, 1, check);
}
};
struct Info{
};
Info operator+(const Info &a, const Info &b){
Info res = Info();
return res;
}
莫队
- 注意保证区间非负
- 要求操作O(1), 因此可以使用分块牺牲查询时间
int block = sqrt(n);
while(block * block < n)block++;
while(block * block > n)block--;
sort(Q.begin() + 1, Q.end(), [&](node a, node b) -> bool{
if(a.l / block != b.l / block){
return a.l < b.l;
}
if((a.l / block) & 1)return a.r > b.r;
return a.r < b. r;
});
auto add = [&](int x) -> void{
};
auto del = [&](int x) -> void{
};
int L = 1, R = 0;
for(int i = 1; i <= q; i++){
auto [l, r, id] = Q[i];
while(L > l)add(--L);
while(R < r)add(++R);
while(L < l)del(L++);
while(R > r)del(R--);
ans[id] = mx;
}
回滚莫队
- O(1) add/del
vector<int> ans(q + 1);
vector<node> Q;
int mx = 0;
int block = sqrt(n);
vector<array<int, 4>> stk;
auto add = [&](int x, int tp) -> void{
if(tp)stk.push_back();
};
auto rollback = [&]() -> void{
while(stk.size()){
}
};
for(int i = 1; i <= q; i++){
int l, r; cin >> l >> r;
if(l / block == r / block){
for(int j = l; j <= r; j++){
add(j, 1);
}
ans[i] = mx;
rollback();
}else Q.push_back({l, r, i, l / block});
}
sort(Q.begin(), Q.end(), [&](node x, node y) -> bool{
if(x.blk != y.blk)return x.l < y.l;
return x.r < y.r;
});
int sz = Q.size();
for(int i = 0, l, r; i < sz; i++){
auto [ll, rr, id, blk] = Q[i];
if(!i || blk != Q[i - 1].blk){
l = min(n + 1, blk * block + block);
r = l - 1;
mx = 0;
cnt.assign(n + 1, 0);
}
while(r < rr)add(++r, 0);
while(l > ll)add(--l, 1);
ans[id] = mx;
rollback();
l = min(n + 1, blk * block + block);
}
回滚删除
#include<bits/stdc++.h>
#define int long long
using namespace std;
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while (0)
void err() {
cout<<endl<<endl;
}
template<class T, class... Ts>
void err(T arg, Ts ... args) {
cout<<fixed<<setprecision(10)<<arg<< ' ';
err(args...);
}
struct node{
int l, r, id, blk;
};
void solve(){
int n, q; cin >> n >> q;
int N = 2e5 + 5;
vector<int> a(n + 1);
for(int i = 1; i <= n; i++)cin >> a[i];
vector<int> ans(q + 1);
vector<node> Q;
int mx = 0;
int block = sqrt(n);
vector<array<int, 2>> stk;
vector<int> cnt(N);
auto del = [&](int x, int tp) -> void{
if(tp)stk.push_back({a[x], mx});
cnt[a[x]]--;
if(!cnt[a[x]]) mx = min(mx, a[x]);
};
auto rollback = [&]() -> void{
while(stk.size()){
auto [x, v] = stk.back();
stk.pop_back();
cnt[x]++;
mx = v;
}
};
for(int i = 1; i <= q; i++){
int l, r; cin >> l >> r;
if(l / block == r / block){
mx = 0;
for(int j = l; j <= r; j++){
cnt[a[j]]++;
}
while(cnt[mx])mx++;
ans[i] = mx;
for(int j = l; j <= r; j++){
cnt[a[j]]--;
}
}else Q.push_back({l, r, i, l / block});
}
sort(Q.begin(), Q.end(), [&](node x, node y) -> bool{
if(x.blk != y.blk)return x.l < y.l;
return x.r > y.r;
});
int sz = Q.size();
for(int i = 0, l, r; i < sz; i++){
auto [ll, rr, id, blk] = Q[i];
if(!i || blk != Q[i - 1].blk){
l = max(1ll, blk * block);
r = n;
cnt.assign(n + 1, 0);
mx = 0;
for(int j = l; j <= r; j++){
cnt[a[j]]++;
}
while(cnt[mx])mx++;
}
while(r > rr)del(r--, 0);
while(l < ll)del(l++, 1);
ans[id] = mx;
rollback();
l = max(1ll, blk * block);
}
for(int i = 1; i <= q; i++){
cout << ans[i] << '\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t=1;//cin>>t;
while(t--)solve();
return 0;
}
bitset(遍历1的位置)
for(int j = r1._Find_first(); j <= n; j = r1._Find_next(j))
斯坦纳树(O())
- 求包含k个点集的最小生成树
constexpr int Max = 1e18;
void solve(){
int n, m, k; cin >> n >> m >> k;
vector<vector<pair<int, int>>> g(n + 1);
for(int i = 1; i <= m; i++){
int u, v, w; cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
vector<int>limit(k + 1);
for(int i = 1; i <= k; i++) cin >> limit[i];
vector dp(n + 1, vector<int>((1 << k), Max));
for(int i = 1; i <= k; i++){
dp[limit[i]][1 << (i - 1)] = 0;
}
auto dijkstra = [&](int s) -> void{
priority_queue<pair<int, int>, vector<pair<int ,int>>, greater<pair<int, int>>>q;
for(int i = 1; i <= n; i++){
if(dp[i][s] != Max){
q.push({dp[i][s], i});
}
}
while(!q.empty()){
auto [val, u] = q.top();
q.pop();
if(val > dp[u][s])continue;
for(auto [v, w] : g[u]){
if(dp[v][s] > dp[u][s] + w){
dp[v][s] = dp[u][s] + w;
q.push({dp[v][s], v});
}
}
}
};
for(int i = 1; i < (1 << k); i++){
for(int s = i; s != 0; s = i & (s - 1)){
for(int j = 1; j <= n; j++){
dp[j][i] = min(dp[j][i], dp[j][s] + dp[j][i ^ s]);
}
}
dijkstra(i);
}
cout << dp[limit[1]][(1 << k) - 1] << '\n';
return ;
}
模拟最小费用流
- 二分图有一边点数很少
struct TwoMCFGraph{
//#define int long long
static constexpr int inf = 1e18;
int n, k;
vector<vector<int>> cost;
vector<int>bl, lim;
vector<vector<set<pair<int, int>>>>q;
TwoMCFGraph(){}
TwoMCFGraph(int n_, int k_){
n = n_;
k = k_;
cost.assign(n + 1, vector<int>(k + 1, inf));
for(int i = 1; i <= n; i++)cost[i][0] = 0;
bl.assign(n + 1, -1);
lim.assign(k + 1, 0);
q.assign(k + 1, vector(k + 1, set<pair<int, int>>()));
}
void add (int x, int c){
for(int i = 1; i <= k; i++){
if(i == c)continue;
q[c][i].insert({cost[x][i] - cost[x][c], x});
}
bl[x] = c;
};
void del (int x){
for(int i = 1; i <= k; i++){
if(i == bl[x])continue;
q[bl[x]][i].erase({cost[x][i] - cost[x][bl[x]], x});
}
bl[x] = -1;
};
int flow(){
int res = 0;
int tot = n;
for(int i = 1; i <= n; i++)add(i, 0);
while(tot--){
vector g(k + 1, vector<int>(k + 1));
for(int i = 0; i <= k; i++){
for(int j = 1; j <= k; j++){
if(q[i][j].empty())g[i][j] = inf;
else g[i][j] = q[i][j].begin() -> first;
}
}
vector<int> dis(k + 1,), pre(k + 1, -1);
vector<int> vis(k + 1, 0);
queue<int> que;
dis[0] = 0;
que.push(0);
while(!que.empty()){
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = 1; i <= k; i++){
if(dis[u] + g[u][i] < dis[i]){
dis[i] = dis[u] + g[u][i];
pre[i] = u;
if(!vis[i]){
vis[i] = 1;
que.push(i);
}
}
}
}
int now = -1;
for(int i = 1; i <= k; i++){
if(lim[i] && (now == -1 || dis[i] < dis[now])){
now = i;
}
}
if(now == -1)break; // 注意这是满流条件
// if(now == -1 || dis[now] > 0)break; // 这是任意流条件
res += dis[now];
lim[now]--;
while(now){
int fa = pre[now];
assert(fa != -1);
int v = q[fa][now].begin() -> second;
del(v);
add(v, now);
now = fa;
}
}
return res;
}
};
void solve(){
int n, k; cin >> n >> k;
TwoMCFGraph g(n, k);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= k; j++){
cin >> g.cost[i][j];
}
}
for(int i = 1; i <= k; i++) cin >> g.lim[i];
cout << g.flow() << '\n';
return ;
}
tarjan
vector<int> dfn(n + 1), low(n + 1);
vector<vector<int>> g(n + 1);
vector<int> bl(n + 1);
int idx = 0, cnt = 0;
stack<int>s;
auto tarjan = [&](auto self, int u) -> void{
dfn[u] = low[u] = ++idx;
s.push(u);
for(auto v : g[u]){
if(!dfn[v]){//还没有访问过
self(self, v);
low[u] = min(low[u], low[v]);
}else if(!bl[v]){//该连通块存在
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]){//是连通块的根节点
cnt++;
int y;
do{
y = s.top();
s.pop();
bl[y] = cnt;
}while(y != u);
}
return ;
};
数论分块
下取整
for(int i = 1, r; i <= n; i = r + 1){
r = n / (n / i);
}
上取整
for(int i = 1; i <= n; ){
int t = (n + i - 1) / i;
if(t <= 1)break;
i = (n + t - 2) / (t - 1);
}
分块
int B = sqrt(n);
vector<int> tag(n / B + 1);
vector<int> sum(n / B + 1);
vector<int> a(n + 1);
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
sum[i / B] += a[i];
}
auto add = [&](int l, int r, int val) -> void{
if(l / B == r / B){
for(int i = l; i <= r; i++){
a[i] += val;
sum[i / B] += val;
}
}else{
for(int i = l / B + 1; i <= r / B - 1; i++){
tag[i] += val;
sum[i] += (min(n + 1, (i + 1) * B) - max(1ll, i * B)) * val;
}
for(int i = l; i < min(n + 1, (l / B + 1) * B); i++){
a[i] += val;
sum[i / B] += val;
}
for(int i = max(1ll, r / B * B); i <= r; i++){
a[i] += val;
sum[i / B] += val;
}
}
};
auto ask = [&](int l, int r) -> int{
int res = 0;
if(l / B == r / B){
for(int i = l; i <= r; i++){
res += a[i] + tag[i / B];
}
}else{
for(int i = l / B + 1; i <= r / B - 1; i++){
res += sum[i];
}
for(int i = l; i < min(n + 1, (l / B + 1) * B); i++){
res += a[i] + tag[i / B];
}
for(int i = max(1ll, r / B * B); i <= r; i++){
res += a[i] + tag[i / B];
}
}
return res;
};
虚树
struct VirtualTree{
static constexpr int k = 20;
int n;
vector<int> dep, dfn, val, cnt;
vector<vector<int>> g;
vector<vector<pair<int, int>>> st;
VirtualTree(vector<vector<int>> &t){
n = t.size() - 1;
dfn.assign(n + 1, 0);
val.assign(n + 1, 0);
cnt.assign(n + 1, 0);
dep.assign(n + 1, 0);
g.assign(n + 1, {});
st.assign(k + 1, vector<pair<int, int>>(n + 1));
int tot = 0;
auto dfs = [&](auto self, int now, int father) -> void{
dfn[now] = ++tot;
dep[now] = dep[father] + 1;
st[0][tot] = {dep[now], father};
for(auto v : t[now]){
if(v == father)continue;
self(self, v, now);
}
};
dfs(dfs, 1, 0);
for(int k = 1; k <= 20; k++){
for(int i = 1; i + (1ll << k) <= n + 1; i++){
st[k][i] = min(st[k - 1][i], st[k - 1][i + (1ll << (k - 1))]);
}
}
}
int lca(int a, int b){
if(a == b)return a;
if(dfn[a] > dfn[b])swap(a, b);
int l = dfn[a] + 1;
int r = dfn[b];
int len = (r - l + 1);
int d = __lg(len);
return min(st[d][l], st[d][r - (1ll << d) + 1]).second;
}
int build(vector<int> &c){
auto v = c;
sort(v.begin(), v.end(), [&](int x, int y) -> bool{
return dfn[x] < dfn[y];
});
int sz = v.size();
for(int i = 1; i < sz; i++){
v.push_back(lca(v[i-1], v[i]));
}
sort(v.begin(), v.end(), [&](int x, int y) -> bool{
return dfn[x] < dfn[y];
});
v.erase(unique(v.begin(), v.end()), v.end());
sz = v.size();
// 建立虚树
for(int i = 1; i < sz; i++){
g[lca(v[i-1], v[i])].push_back(v[i]);
}
// 跑贡献
int ans = 0;
for(auto x : c)cnt[x] = 1;
auto dfs = [&](auto self, int now) -> void{
for(auto x : g[now]){
self(self, x);
val[x] += cnt[x] * (dep[x] - dep[now]);
ans += val[now] * cnt[x] + val[x] * cnt[now];
val[now] += val[x];
cnt[now] += cnt[x];
}
};
dfs(dfs, v[0]);
// 记得清空
for(auto x : v){
vector<int>().swap(g[x]);
val[x] = 0;
cnt[x] = 0;
}
return ans;
}
};
树状数组
template<class Info>
struct Fenwick{
// #define lowbit(x) ((x) & (-x))
vector<Info> tr;
int n;
Fenwick(int n_) : n(n_), tr(n_ + 1){}
void add(int x, Info val){
while(x <= n){
tr[x] = tr[x] + val;
x += lowbit(x);
}
}
Info ask(int x){
Info res = Info();
while(x > 0){
res = res + tr[x];
x -= lowbit(x);
}
return res;
}
Info rangeAsk(int l, int r){
return ask(r) - ask(l - 1);
}
template<class F>
int find(F &&check){
int p = 0;
Info res = Info();
int d = __lg(n);
for(int i = d; i >= 0; i--){
int v = p + (1ll << i);
if(v <= n && check(res + tr[v])){
p = v;
res = res + tr[p];
}
}
return p;
}
};
struct Info{
int sum = 0, cnt = 0;
};
Info operator+ (const Info &a, const Info &b){
Info res = Info();
res.sum = a.sum + b.sum;
res.cnt = a.cnt + b.cnt;
return res;
}
Info operator- (const Info &a, const Info &b){
Info res = Info();
res.sum = a.sum - b.sum;
res.cnt = a.cnt - b.cnt;
return res;
}
ST表
template<class T,
class Cmp = std::less<T>>
struct ST{
int n, k;
const Cmp cmp = Cmp();
vector<vector<T>> st;
ST(){}
ST(const vector<T> &a){
init(a);
}
void init(const vector<T> &a){
n = a.size() - 1;
k = __lg(n);
st.resize(k + 1, vector<T>(n + 1));
for(int i = 1; i <= n; i++){
st[0][i] = a[i];
}
for(int s = 1; s <= k; s++){
for(int i = 1; i + (1 << s) <= n + 1; i++){
st[s][i] = min(st[s - 1][i], st[s - 1][i + (1 << (s - 1))], cmp);
}
}
}
T get(int l, int r){
int d = __lg(r - l + 1);
return min(st[d][l], st[d][r - (1 << d) + 1], cmp);
}
};
组合数
constexpr int maxn = 1e5 + 5;
mint f[maxn], inv[maxn];
void init(){
f[0] = inv[0] = 1;
for(int i = 1; i < maxn; i++){
f[i] = f[i - 1] * i;
}
inv[maxn - 1] = f[maxn - 1].inv();
for(int i = maxn - 1; i >= 1; i--){
inv[i - 1] = inv[i] * i;
}
}
mint C(int n, int m){
if(n < 0 || m < 0 || n < m)return 0;
return f[n] * inv[m] * inv[n - m];
}