struct Heap{
    priority_queue<ll>q1,q2;
    inline void push(ll x){q1.push(x);}
    inline void erase(ll x){q2.push(x);}
    inline void updata(){while(!q1.empty()&&!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();}
    inline ll top(){updata();return q1.top();}
}Q;

ST表

静态求区间最大值,基于倍增的思想

int N,M;
int arr[maxn],Log2[maxn];//原始数组,log2(x)数组
int f[maxn][20];//F[i][j]: arr[i~i+2^j-1]的最大值

void ST_init(){ //初始化所有长度为2^x的区间最大值
    for(int i = 1;i<=N;i++) Log2[i] = log(i)/log(2); //初始化log求值,之后O(1)取值
    for(int i = 1;i<=N;i++) f[i][0] = arr[i];
    int len = log(N)/log(2) +1;
    for(int j = 1;j<len;j++){
        for(int i = 1;i<=N-(1<<j)+1;i++){
            f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
}
int query(int l,int r){ //查询arr[l~r]区间的最值
    int k = Log2[r-l+1];
    return max(f[l][k],f[r-(1<<k)+1][k]);
}

并查集

int find(int x){
    return fa[x] == x? x: fa[x] = find(fa[x]);
}
void join(int x,int y){
    int fx = find(x),fy = find(y);
    if(fx != fy) fa[fx] = fy;
}
for(int i = 1;i<=N;i++) fa[i] = i;//一定要初始化

分块

以求和为例

ll arr[maxn],base[maxn],res[maxn],B;//B:块的大小
void init(){ //分块初始化:每一个块维护[id*B,(id+1)*B],id是块的编号
    for(int i = 1;i<=N;i++) res[i/B] += arr[i];
}
void modify(int l,int r,int v){ //sqrt(N)修改复杂度
    int bl = l/B,br = r/B;
    ll ans = 0;
    if(bl == br){
        for(int i = l;i<=r;i++) arr[i] += v,res[bl] += v;
    }else{
        for(int i = l;i<(bl+1)*B;i++) arr[i]+=v,res[bl] += v;//小块
        for(int i = bl+1;i<=br-1;i++) base[i]+=v,res[i] += (ll)v*B;//大块
        for(int i = br*B;i<=r;i++) arr[i] +=v,res[br] += v;//小块
    }
}
ll query(int l,int r){//sqrt(N)查询复杂度
    int bl = l/B, br = r/B;
    ll ans = 0;
    if(bl == br){
        for(int i = l;i<=r;i++) ans += arr[i] + base[bl];
    }else{
        for(int i = l;i<(bl+1)*B;i++) ans += arr[i] + base[bl];
        for(int i = bl+1;i<=br-1;i++) ans += res[i];
        for(int i = br*B;i<=r;i++) ans += arr[i] + base[br];
    }
    return ans;
}

奇奇怪挂的数据结构

马拉车算法

string s;
int ans[maxn],str[maxn],lef[maxn]; 
//ans:每一点的回文半径,str:插#字符后的字符串 lef:以某个为左边界的最长回文子串长度
int build(const string &s){
    int n = s.length(), m = (n + 1)*2, ret = 0;
    str[0] = '$'; str[m] = '@'; str[1] = '#'; ans[1] = 1;
    for (int i = 1; i <= n; i++) 
        str[i*2] = s[i - 1], str[i*2+1] = '#';
    ans[1] = 1;
    for (int r = 0, p = 0, i = 2; i < m; ++i){
        if (r > i) ans[i] = min(r - i, ans[p * 2 - i]); 
        else ans[i] = 1; 
        while(str[i - ans[i]] == str[i + ans[i]]) ++ans[i];
        if (i + ans[i] > r) r = i + ans[i], p = i;
        ret = max(ret, ans[i] - 1);
    }
        // 计算维护以每个位置为起点的最长回文串
        for (int i = 0; i <= m; i++) lef[i] = 0;
        for (int i = 2; i < m; i++) if (lef[i - ans[i] + 1] < i + 1) lef[i - ans[i] + 1] = i + 1;
        for (int i = 1; i <= m; i++) if (lef[i] < lef[i - 1]) lef[i] = lef[i - 1];
    return ret;//最长回文串的长度
}
 int mid(int x, bool odd){ 
     //求以x为中心的最长回文子串长度,若是求偶回文串,这里中心认为是中间靠左
        if (odd) return ans[(x + 1) << 1] - 1;
        return ans[(x + 1) << 1 | 1] - 1;
    }
int left(int x){ 
    //求以x为左端点的最长回文串的长度
    return lef[(x + 1) << 1] - ((x+1) << 1); 
}

树状数组

二维树状数组 [单点修改、区间查询]

int N,M;//N*M的矩阵
int tr[1111][1111];
int lowbit(int x){
    return x&-x;
}
void add(int x,int y,int v){
    for(int i = x;i<=N;i += lowbit(i)){
        for(int j = y;j<=M;j += lowbit(j)){
            tr[i][j] += v;
        }
    }
}
ll pre_sum(int x,int y){ //查询(1,1)到(x,y)矩阵和
    ll sum = 0;
    for(int i = x;i>=1;i -= lowbit(i)){
        for(int j = y;j>=1;j -= lowbit(j)){
            sum += tr[i][j];
        }
    }
    return sum;
}
ll query(int x1,int y1,int x2,int y2){ //查询(x1,y2)到(x2,y2)的矩阵和
    return pre_sum(x2,y2) - pre_sum(x1-1,y2) - pre_sum(x2,y1-1) + pre_sum(x1-1,y1-1);
}

二维树状数组 [区间修改,单点查询]

int tr[1010][1010];//NxN的矩阵

int lowbit(int x){
    return x&-x;
}
void add(int x,int y,int v){
    for(int i = x;i<=N;i += lowbit(i))
        for(int j = y;j<=N;j += lowbit(j))
            tr[i][j] += v;
}
int query(int x,int y){
    int sum = 0;
    for(int i = x;i>=1;i -= lowbit(i))
        for(int j = y;j>=1;j -= lowbit(j))
            sum += tr[i][j];
    return sum;
}
//给左上角(x1,y1) ,右下角(x2,y2)的矩阵+v
add(x1,y1,+v);
add(x1,y2+1,-v);
add(x2+1,y1,-v);
add(x2+1,y2+1,+v);