四维的板子

乱七八糟

IO优化

//适用于非负整数
template<class T>
void read(T&ret) {
	char c;
	ret=0;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')ret=ret*10+(c-'0'),c=getchar();
}
//适用于整数
template<class T>
bool read(T&ret) {
	char c;
	int sgn;
	if(c=getchar(),c==EOF)return 0;//EOF
	while(c!='-'&&(c<'0'||c>'9'))c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9')ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
//适用于整数,(int,long long,float,double)
template<class T>
bool read(T&ret) {
	char c;
	int sgn;
	T bit=0.1;
	if(c=getchar(),c==EOF)return 0;
	while(c!='-'&&c!='.'&&(c<'0'||c>'9'))c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9')ret=ret*10+(c-'0');
	if(c==' '||c=='\n') {
		ret*=sgn;
		return 1;
	}
	while(c=getchar(),c>='0'&&c<='9')ret+=(c-'0')*bit,bit/=10;
	ret*=sgn;
	return 1;
}
//输出外挂
void out(int x) {
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
ios::sync_with_stdio(0),cin.tie(0);
cout<<fixed<<setprecision(2)<<3.0<<endl;
cout<<setfill('0')<<setw(2)<<3<<endl;

优先级 

优先级

运算符

1

[]  ()  .  ->  ++ --

2

-  (类型)  ++  --  * &  !  ~  sizeof

3

/  *  %

4

+  -

5

<<  >>

6

>  >=  <  <=

7

==  !=

8

&

9

^

10

|

11

&&

12

||

13

?:

14

=  /=  *=  %=  +=  -=  <<=  >>=  &=  ^=  |=

15

,

string

getline(cin,str);//带空格输入字符串
str.substr(p0,len);//其中len可以不填,默认取到末尾。

str.erase(p0,len);
str.erase(str.begin()+i);//删除第i个

str1.insert(p0,str2,pos,len);//后两个参数截取str2,可以省略
s.insert(int p0,int n,char c);//在p0处插入n个字符c

s1.replace(p0,len0,str2,pos,len);//删除p0开始的len0个字符,然后在p0处插入串str2中从pos开始的len个字符

str1.find(str2,pos)//从前往后,查找成功时返回所在位置,失败返回string::npos的值 (-1)
str1.rfind(str2,pos)//从pos开始从后向前查找字符串str2中字符串在当前串中的位置

vector

v.front()     // 传回第一个数据。
v.back()      // 传回最后一个数据,不检查这个数据是否存在。
v.erase(pos)  // 删除pos位置的数据,传回下一个数据的位置。
v.erase(beg,end)  //删除[beg,end)区间的数据,传回下一个数据的位置。
v.insert(pos,elem)    // 在pos位置插入一个elem拷贝,传回新数据位置。
v.insert(pos,n,elem)  // 在pos位置插入n个elem数据。无返回值。
v.insert(pos,beg,end) // 在pos位置插入在[beg,end)区间的数据。无返回值。

priority_queue

priority_queue<int>q;//top是最大值
priority_queue<int,vector<int>,greater<int> >q;//top是最小值
bool operator<(Node a,Node b){return a.x<b.x;}//放到结构体里面时需要加const
struct cmp{bool operator()(int a,int b){return a<b;}};
priority_queue<int,vector<int>,cmp_key>q;

rope 

#include <ext/rope>//可持久化平衡树
using namespace __gnu_cxx;
rope<int>r;
r.push_back(x);//在末尾添加x
r.insert(pos, x); //在pos插入x
r.erase(pos, x); //从pos开始删除x个
r.copy(pos, len, x); //从pos开始到pos+len为止用x代替
r.replace(pos, x); //从pos开始换成x
r.substr(pos, x); //提取pos开始x个
r[x]; //访问第x个元素

bitset

bitset<5>b;//坐标从后往前计数,高位在前
bitset<5>b(13);
bitset<5>b("1101");
b.count();//count函数用来求bitset中1的位数,一共3
b.size();//size函数用来求bitset的大小,一共5
b.any();//any函数检查bitset中是否有1
b.none();//none函数检查bitset中是否没有1
b.all();//all函数检查bitset中是全部为1
foo.flip();//flip函数不指定参数时,将bitset每一位全部取反
foo.set();//set函数不指定参数时,将bitset的每一位全部置为1
foo.reset();//reset函数不传参数时将bitset的每一位全部置为0
string s = foo.to_string();//将bitset转换成string类型
unsigned long a = foo.to_ulong();//将bitset转换成unsigned long类型
unsigned long long b = foo.to_ullong();//将bitset转换成unsigned long long类型 

rand 

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
double rnd(double l, double r){return uniform_real_distribution<double>(l,r)(rng);}
int rnd(int l,int r){return uniform_int_distribution<int>(l,r)(rng);}

数据结构

主席树

//本模板是离散后对权值建树
#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
const int N=2e5+10;
struct TR
{
    int sum,lo,ro;
}tr[N<<5];
int tr_cnt;//之后需要初始化=0
int n,m,q,arr[N],brr[N],rt[N];//m是权值的数量
void build(int &o,int l=1,int r=m)
{
    o=++tr_cnt;
    //tr[o].sum=0;
    if(l==r)return;
    build(tr[o].lo,l,mid);
    build(tr[o].ro,mid+1,r);
}
void update(int p,int v,int pre,int &o,int l=1,int r=m)
{
    o=++tr_cnt;
    tr[o]=tr[pre];
    tr[o].sum+=v;//都是+1
    if(l==r)return;
    if(p<=mid)update(p,v,tr[pre].lo,tr[o].lo,l,mid);
    else update(p,v,tr[pre].ro,tr[o].ro,mid+1,r);
}
//u和v是两个线段树的根,相减后的线段树求第k个的下标位置
int query(int k,int u,int v,int l=1,int r=m)
{
    if(l==r)return l;

    int tmp=tr[tr[v].lo].sum-tr[tr[u].lo].sum;
    if(tmp>=k)return query(k,tr[u].lo,tr[v].lo,l,mid);
    else return query(k-tmp,tr[u].ro,tr[v].ro,mid+1,r);
}
int main()
{
    int n,q;scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",arr+i),brr[i]=arr[i];
    sort(brr+1,brr+1+n);
    m=unique(brr+1,brr+1+n)-brr-1;

    build(rt[0]);
    for(int i=1;i<=n;i++)
    {
        int p=lower_bound(brr+1,brr+1+m,arr[i])-brr;
        update(p,1,rt[i-1],rt[i]);
    }
    while(q--)
    {
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        printf("%d\n",brr[query(k,rt[u-1],rt[v])]);
    }
	return 0;
}

树状数组

namespace BTree
{
    const int N = 5e5 + 10;
    int n, c[N];
    int lb(int a) {return a & (-a);}
    void add(int p, int v)
    {
        for(; p <= n; p += lb(p))
            c[p] += v;
    }
    int query(int p)
    {
        int ret = 0;
        for(; p; p -= lb(p))
            ret += c[p];
        return ret;
    }
};

RMQ

//O(20*n)复杂度,O(1)求1~n的最大最小值
//ma[j][i]代表i~i+(1<<j)-1的最值
struct RMQ
{
    static const int N=1e5+10;
    int n,ma[20][N],lg[N];
    void build(int n){
        lg[0]=-1;
        for(int i=1;i<=n;i++){
            lg[i]=lg[i-1]+(i&i-1?0:1);
            ma[0][i]=arr[i].se;
        }
        for(int j=1;j<=lg[n];j++)for(int i=1;i<=n-(1<<j)+1;i++)
            ma[j][i]=max(ma[j-1][i], ma[j-1][i+(1<<j-1)]);
    }
    int query(int l, int r){
        int k=lg[r-l+1];
        return max(ma[k][l], ma[k][r-(1<<k)+1]);
    }
}sw;

线段树合并/分裂

#include <bits/stdc++.h>
#define mid (l+r>>1)
#define ll long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10;
int n,m,cnt,seq = 1,bac[N<<5],lo[N<<5],ro[N<<5],rt[N];
ll val[N << 5];
int newnod () {return bac[cnt--];}//从库中取出某下标
void del (int o) {bac[++cnt] = o, lo[o] = ro[o] = val[o] = 0;}//把下标回收
void add (int p, int v, int &o, int l = 1, int r = n)
{//单点加操作
    if (!o)o = newnod();
    val[o] += v;
    if (l == r)return;
    if (p <= mid)add(p, v, lo[o], l, mid);
    else add(p, v, ro[o], mid + 1, r);
}
ll query (int ql, int qr, int o, int l = 1, int r = n)
{//查询区间和
    if (ql <= l && r <= qr)return val[o];
    ll ret = 0;
    if(ql <= mid)ret = query(ql, qr, lo[o], l, mid);
    if(qr > mid)ret += query(ql, qr, ro[o], mid + 1, r);
    return ret;
}
int kth (int k, int o, int l = 1, int r = n)
{//查询o处线段树第k小,本题不用离散化
    if (l == r)return l;
    if (val[lo[o]] >= k)return kth(k, lo[o], l, mid);
    else return kth(k - val[lo[o]], ro[o], mid + 1, r);
}
int merge (int x, int y)
{//合并下标x和y节点处的线段树,返回合并后的下标
    if (!x || !y)return x+y;
    val[x] += val[y];
    lo[x] = merge(lo[x], lo[y]);
    ro[x] = merge(ro[x], ro[y]);
    del(y);
    return x;
}
void split (int x, int &y, ll k)
{//把x的前k个保留,剩下的分给y
    if (!x)return;
    y = newnod();
    ll v = val[lo[x]];
    if (k > v)split(ro[x], ro[y], k - v);
    else swap(ro[x], ro[y]);
    if (k < v)split(lo[x], lo[y], k);
    val[y]=val[x]-k,val[x]=k;
    return;
}
int main ()
{
    for(int i = 1; i < (N << 5); i++)bac[++cnt] = i;//把下标存进库中
    cin >> n >> m;
    for (int i = 1,a; i <= n; i++){cin >> a;add(i, a, rt[1]);}
    for (int i = 1,op,p,x,l,r,q,t,k; i <= m; i++)
    {
        cin >> op;
        if (op == 0)
        {//将可重集p中大于等于l且小于等于r的值放入一个新的可重集中
            cin >> p >> l >> r;
            ll k1 = query(1, r, rt[p]), k2 = query(l, r, rt[p]);
            int tmp;
            split(rt[p], rt[++seq], k1 - k2);//先把l~n分裂给新集合
            split(rt[seq], tmp, k2);//再把r~n分裂出来给tmp
            rt[p] = merge(rt[p], tmp);//把tmp还给p
        }
        else if (op == 1)
        {//将可重集 t 中的数放入可重集 p,且清空可重集 t
            cin >> p >> t;
            rt[p] = merge(rt[p], rt[t]);
        }
        else if (op == 2)
        {//在 p 这个可重集中加入 x 个数字 q
            cin >> p >> x >> q;
            add(q, x, rt[p]);
        }
        else if (op == 3)
        {//查询可重集 p 中大于等于 x 且小于等于 y 的值的个数。
            cin >> p >> l >> r;
            cout << query(l, r, rt[p]) << endl;
        }
        else if (op == 4)
        {//查询在 p 这个可重集中第 k 小的数,不存在时输出 -1
            cin >> p >> k;
            cout<<(val[rt[p]] < k?-1:kth(k, rt[p]))<<endl;
        }
    }
}

平衡树

#include<bits/stdc++.h>
const int N = 1e5+5;
using namespace std;

int n;
int tot,root;
int w[N],num[N],sz[N],fa[N],son[N][2];

void update(int x) {
	sz[x]=sz[son[x][0]]+sz[son[x][1]]+num[x];
}

//void pushdown(int x) {
//	do something...
//}

void rotate(int x) {
//    pushdown(fa[x]);pushdown(x);
	int y=fa[x],z=fa[y],t=(son[y][0]==x);
	fa[y]=x;fa[x]=z;
	if(z) son[z][son[z][1]==y]=x;
	son[y][!t]=son[x][t];fa[son[x][t]]=y;
	son[x][t]=y;
	update(y);update(x);
}

void splay(int x,int f) {
//    pushdown(x);
	while(fa[x]!=f) {
		int y=fa[x],z=fa[y];
		if(z!=f) {
			if(son[y][0]==x^son[z][0]==y)rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if(!f)root=x;
}

void insert(int val,int &x=root,int f=0) {
	if(!x) {
		x=++tot;fa[x]=f;
		son[x][0]=son[x][1]=0;
		w[x]=val;sz[x]=num[x]=1;
		splay(x,0);
		return;
	}
	if(val==w[x]) {
		sz[x]++;num[x]++;
		splay(x,0);
		return;
	}
	insert(val,son[x][val>w[x]],x);
	update(x);
}

int get(int val) {
	int x=root;
//    pushdown(x);
	while(x&&w[x]!=val) {
		x=son[x][val>w[x]];
//    pushdown(x);
	}
	return x;
}

void delet(int w) {
	int x=get(w);
	if(!x)return;
	splay(x,0);
	if(num[x]>1) {
		num[x]--;sz[x]--;
		return;
	}
	if(!son[x][0]||!son[x][1])root=son[x][0]+son[x][1];
	else {
		int y=son[x][1];
		while(son[y][0])y=son[y][0];
		splay(y,x);
		fa[son[x][0]]=y;
		son[y][0]=son[x][0];
		root=y;
		son[x][0]=son[x][1]=0;
	}
	fa[root]=0;
	update(root);
}

int getrank(int val) {
	int x=root,ret=0,last=0;
	while(x) {
		last=x;
		if(val>w[x]) {
			ret+=sz[son[x][0]]+num[x];
			x=son[x][1];
		} else if(val==w[x]) {
			ret+=sz[son[x][0]];
			break;
		} else {
			x=son[x][0];
		}
	}
	if(last)splay(last,0);
	return ret+1;
}

int kth(int k) {
	int x=root;
//    pushdown(x);
	while(k<=sz[son[x][0]]||k>sz[son[x][0]]+num[x]) {
		if(k<=sz[son[x][0]])x=son[x][0];
		else k-=sz[son[x][0]]+num[x],x=son[x][1];
//    pushdown(x);
	}
	return w[x];
}

int getpre(int val) {
	int x=root,ret=0,last=0;
	while(x) {
		last=x;
		if(val>w[x]) {
			ret=w[x];
			x=son[x][1];
		} else {
			x=son[x][0];
		}
	}
	if(last)splay(last,0);
	return ret;
}

int getne(int val) {
	int x=root,ret=0,last=0;
	while(x) {
		last=x;
		if(val<w[x]) {
			ret=w[x];
			x=son[x][0];
		} else {
			x=son[x][1];
		}
	}
	if(last)splay(last,0);
	return ret;
}

int main() {
	scanf("%d",&n);
	for(int i=1,x,y; i<=n; ++i) {
		scanf("%d%d",&x,&y);
		if(x==1)insert(y);
		if(x==2)delet(y);
		if(x==3)printf("%d\n",getrank(y));
		if(x==4)printf("%d\n",kth(y));
		if(x==5)printf("%d\n",getpre(y));
		if(x==6)printf("%d\n",getne(y));
	}
}

整体二分

#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int n,m,cnt,ans[N];
struct A
{
    int l,r,k,id,op;
}q[N<<1],q1[N<<1],q2[N<<1];

int c[N];
int lb(int a){return a&-a;}
void add(int p,int v)
{
    for(;p<=n;p+=lb(p))
        c[p]+=v;
}
int query(int p)
{
    int ret=0;
    for(;p;p-=lb(p))
        ret+=c[p];
    return ret;
}

void solve(int l,int r,int ql,int qr)
{
    if(ql>qr)return;
    if(l==r)
    {
        for(int i=ql;i<=qr;i++)if(q[i].op==2)
            ans[q[i].id]=l;
        return;
    }

    int cnt1=0,cnt2=0;
    for(int i=ql;i<=qr;i++)
    {
        if(q[i].op==1)
        {
            if(q[i].l<=mid)q1[++cnt1]=q[i],add(q[i].id,1);
            else q2[++cnt2]=q[i];
        }
        else
        {
            int t=query(q[i].r)-query(q[i].l-1);
            if(q[i].k<=t) q1[++cnt1]=q[i];
            else q[i].k-=t,q2[++cnt2]=q[i];
        }
    }
    for(int i=1;i<=cnt1;i++)if(q1[i].op==1)add(q1[i].id,-1);
    for(int i=1;i<=cnt1;i++)q[i+ql-1]=q1[i];
    for(int i=1;i<=cnt2;i++)q[ql+cnt1+i-1]=q2[i];
    solve(l,mid,ql,ql+cnt1-1);
    solve(mid+1,r,ql+cnt1,qr);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cnt++;
        cin>>q[cnt].l;
        q[cnt].id=i,q[cnt].op=1;
    }
    for(int i=1;i<=m;i++)
    {
        cnt++;
        cin>>q[cnt].l>>q[cnt].r>>q[cnt].k;
        q[cnt].id=i,q[cnt].op=2;
    }
    solve(-inf,inf,1,cnt);
    for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
    return 0;
}

可撤销并查集 

struct UFS {
    struct A{int tp,id,w;};
    stack<A> stk;
    vector<int>fa,rnk;
    UFS(int n) {
        fa.assign(n+1,0);
        rnk.assign(n+1,0);
        for (int i = 0; i <= n; ++i) fa[i] = i;
    }
    int Find(int x) {
        while(x^fa[x]) x = fa[x];
        return x;
    }
    int Merge(int x, int y) {   //返回本次合并栈的增加数量
        int ret=0;
        x = Find(x), y = Find(y);
        if(x == y) return 0;
        ans++;
        if(rnk[x] <= rnk[y]) {
            stk.push({1, x, fa[x]});ret++;
            fa[x] = y;
            if(rnk[x] == rnk[y]) {
                stk.push({2, y, rnk[y]});ret++;
                rnk[y]++;
            }
        }
        else {
            stk.push({1, y, fa[y]});ret++;
            fa[y] = x;
        }
        return ret;
    }
    void Undo() {
        A a=stk.top();stk.pop();
        if(a.tp==1)fa[a.id]=a.w,ans--;
        else rnk[a.id]=a.w;
    }
};

图论

最小生成树

/*
* Prim 求无向图最小生成树
* 无堆优化O(n*n),空间O(n*n),适用于稠密图
* 耗费矩阵 cost[N][N],标号从 0 开始,0~n-1
* 矩阵cost[N][N],初始化为inf,注意重边问题
* 返回最小生成树的权值,返回 -1 表示原图不连通
*/
bool vis[N];
int n, lowc[N], cost[N][N];
//点是 0 n-1
int Prim()
{
    int ret = 0;
    memset(vis, false, sizeof(*vis)*n);
    vis[0] = true;
    for(int i = 1; i < n; i++)
        lowc[i] = cost[0][i];
    for(int i = 1; i < n; i++)
    {
        int mi = inf;
        int id = -1;
        for(int j = 0; j < n; j++)
            if(!vis[j] && mi > lowc[j])
            {
                mi = lowc[j];
                id = j;
            }
        if(mi == inf)
            return -1;//原图不连通
        ret += mi;
        vis[id] = true;
        for(int j = 0; j < n; j++)
            if(!vis[j] && lowc[j] > cost[id][j])
                lowc[j] = cost[id][j];
    }
    return ret;
}
/*
* Kruskal 算法求 MST
* 适用于稀疏图,O(Elog(E))
*/
tri edg[M];//普通存边(非前向星)
int edg_cnt;//记得初始化为 0
void addedg(int a, int b, int c) {edg[edg_cnt++] = {a, b, c};}
int father[N];//并查集
int ff(int a) {return father[a] == a ? a : father[a] = ff(father[a]);}
//传入点数,返回最小生成树的权值,如果不连通返回 -1
int Kruskal()
{
    for(int i = 1; i <= n; i++)
        father[i] = i;
    sort(edg, edg + edg_cnt, [](tri a, tri b) {return a.c < b.c;});
    int cnt = 0, ret = 0; //计算加入的边数
    for(int i = 0; i < edg_cnt; i++)
    {
        int fa = ff(edg[i].a), fb = ff(edg[i].b);
        if(fa != fb)
        {
            ret += edg[i].c;
            father[fa] = fb;
            cnt++;
        }
        if(cnt == n - 1)
            return ret;
    }
    return -1;
}

最短路

struct Dij
{
    int n,s;
    vector<bool>vis;
    vector<ll>dis;
    vector<vector<pair<int,ll> > >edg;
    Dij(int n,int s=0)
    {
        this->n=n;
        this->s=s;
        vis.assign(n,0);
        dis.assign(n,linf);
        edg.assign(n,{});
    }
    void add_edg(int u,int v,int w){edg[u].push_back({v,w});};
    void solve()
    {
        dis[s]=0;
        priority_queue<pair<ll,int>>q;
        q.push({0,s});
        while(!q.empty())
        {
            int u=q.top().se;q.pop();
            if(vis[u])continue;
            vis[u]=1;
            for(auto [v,w]:edg[u])if(!vis[v]&&dis[u]+w<dis[v])
            {
                dis[v]=dis[u]+w;
                q.push({-dis[v],v});
            }
        }
    }
};
struct SPFA
{
    vector<bool>vis;vector<ll>dis;vector<int>cnt;
    vector<vector<pair<int,ll>>>edg;
    int n,s;
    SPFA(int n,int s=1)
    {
        this->n=n;this->s=s;
        vis.assign(n+1,0);
        dis.assign(n+1,inf);
        edg.assign(n+1,{});
        cnt.assign(n+1,0);
    }
    void add_edg(int u,int v,ll w){edg[u].push_back({v,w});}
    bool solve()
    {
        dis[s]=0;
        queue<int>q;
        q.push(s);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值