容易忘/码量大/骗分效果好的模板(写给自己看)

字符串:

manacher:

     //该程序实现找出一个字符串中最长回文子串的长度
    scanf("%s",a+1),n=strlen(a+1),s[++t]='#';for(int i=1;i<=n;i++)s[++t]=a[i],s[++t]='#';
    for(int i=1,mid=0;i<=t;i++){
        if(i<=mid+d[mid])d[i]=min(mid+d[mid]-i,d[(mid<<1)-i]);
        int l=i-d[i],r=i+d[i];
        while(l>=1&&r<=t&&s[l]==s[r])l--,r++;l++,r--;
        d[i]=(r-l+1)>>1;if(r>mid+d[mid])mid=i;ans=max(ans,d[i]);
    }write(ans);

Z 函数:

//该代码求字符串与自己每一个后缀的 LCP(最长公共前缀) 长度
void getz(string s){
	int op=s.size();z[0]=0;
	for(int i=1,l=0,r=0;i<op;i++){
		if(i<=r&&z[i-l]<r-i+1)z[i]=z[i-l];
		else{
			z[i]=max(0ll,r-i+1);
			while(i+z[i]<op&&s[z[i]]==s[i+z[i]])z[i]++;
			l=i,r=i+z[i]-1;
		}
	}
}

数学:

exgcd(极其重要,好丢脸,这都会忘):

//该程序求解 ax+by+c=0 方程的解
#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();return x*w;
}
inline void write(ll x){
	if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
ll A=read(),B=read(),C=read(),x,y;
ll exgcd(ll a,ll b){//exgcd部分
    if(b==0){x=1,y=0;return a;}
    ll tmp=exgcd(b,a%b),kkk=x;
    x=y,y=kkk-a/b*y;
    return tmp;
}
int main(){
    C=-C;
    ll op=exgcd(A,B);
    if((C+op)%op!=0){printf("-1");return 0;}
    x*=C/op,y*=C/op;
    write(x),putchar(' '),write(y);
    return 0;
}

crt(待补充):


excrt(待补充):


线性求逆元:

	scanf("%lld%lld",&n,&p),inv[1]=1;
	for(int i=2;i<=n;i++)inv[i]=((p-p/i)*inv[(p+i)%i]+p)%p;
	for(int i=1;i<=n;i++)printf("%lld\n",inv[i]);

快速幂求一个数逆元:

\(i^{-1}=i^{p-2} mod p\)(i 为要求的数,p 为模数,且必须为质数)。

欧拉定理:

\(当 a,m\in \mathbb{Z},且 \gcd(a,m)=1 时有: a^{\varphi(m)}\equiv 1\pmod{m}。\)

扩展欧拉定理:

\(a,m\in \mathbb{Z}\) 时有:
\(a^b\equiv\left\{\begin{matrix}a^b&,b < \varphi(m)\\a^{b\bmod\varphi(m)+\varphi(m)}&,b\ge\varphi(m)\end{matrix}\right.\pmod m\)

计算几何:

目前啥都不会,待补充。

图论:

Tarjan:

void tarjan(int x){
    low[x]=dfn[x]=++num;//dfn 是 dfs 序,low 是最高处结点(表述不准确,意会即可)
    st[++t]=x;//st 是栈
    for(int i=h[x];i!=-1;i=e[i].nxt){
        int u=e[i].y;
        if(!dfn[u]){
            tarjan(u);
            low[x]=min(low[x],low[u]);
        }
        else if(!scc[u])low[x]=min(low[x],dfn[u]);//dfn!!不是 low
    }//递归
    if(dfn[x]==low[x]){//环已成形,开始染色
        sccnum++;
        int w=0;
        while(t){
            scc[st[t]]=sccnum;
            if(st[t]==x){
                if(w)ans++;
                t--;
                break;
            }
            t--,w=1;
        }
    }
}

割点:

//luogu P3388
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,cnt,h[20005],vis[20005],dfn[20005],low[20005],num,sum,ans[20005];
struct node{
	int y,nxt;
}e[300005];
void add(int noi,int ioi){e[cnt].y=ioi,e[cnt].nxt=h[noi],h[noi]=cnt++;}
void dfs(int u,int fa){
	int fsb=0;
	vis[u]=1,dfn[u]=low[u]=++num;
	for(int i=h[u];i!=-1;i=e[i].nxt){
		if(!vis[e[i].y]){
			dfs(e[i].y,fa);
			low[u]=min(low[u],low[e[i].y]);
			if(low[e[i].y]>=dfn[u]&&u!=fa)ans[u]=1;
			if(u==fa)fsb++;
		}
		low[u]=min(low[u],dfn[e[i].y]);
	}
	if(fsb>=2&&u==fa)ans[u]=1;
}
signed main(){
	memset(h,-1,sizeof(h));
	scanf("%lld%lld",&n,&m);
	while(m--){
		int oi,noi;
		scanf("%lld%lld",&oi,&noi);
		add(oi,noi),add(noi,oi);
	}
	for(int i=1;i<=n;i++)if(!vis[i])dfs(i,i);
	for(int i=1;i<=n;i++)if(ans[i])sum++;
	printf("%lld\n",sum);
	for(int i=1;i<=n;i++)if(ans[i])printf("%lld ",i);
	return 0;
}

网络流(dinic,这个好像不容易忘,不过码量大):

bool bfs(){
    memset(d,0,sizeof(d)),he=ti=0,q[++ti]=s,d[s]=1;
    while(he<ti){
        int u=q[++he];
        for(int i=h[u];i!=-1;i=e[i].nxt)
            if(!d[v]&&e[i].c){
                d[v]=d[u]+1,q[++ti]=v;
            }
    }
    return d[t]!=0;
}
int dfs(int u,int fl){
    if(u==t)return fl;
    int an=0;
    for(int i=cur[u];i!=-1&&fl;i=e[i].nxt){
        cur[u]=i;
        if(e[i].c&&d[v]==d[u]+1){
            int op=dfs(v,min(fl,e[i].c));
            e[i].c-=op,e[i^1].c+=op,an+=op,fl-=op;
        }
    }
    if(!an)cur[u]=-1;
    return an;
}
int dinic(){int an=0;while(bfs()){for(int i=s;i<=t;i++)cur[i]=h[i];an+=dfs(s,inf);}return an;}

最小费用最大流(dinic 版本,SPFA 队列用 STL 吧,毕竟各元素要多次入队,vis数组dfs时不置回零,达到单路增广使常数更优):

#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define INF 0x3f
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-48,ch=getchar();return w==1?x:-x;
}
inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
ll n=read(),m=read(),S=read(),T=read(),h[5005],cur[5005],d[5005],cnt,mf,mc;
bool vis[5005];
struct node{ll y,c,w,nxt;}e[1090005];//有点反人类?c表示流量,w表示花费 
void add(int o1,int o2,int o3,int o4){e[cnt]={o2,o3,o4,h[o1]},h[o1]=cnt++;}
bool SPFA(){
	for(int i=0;i<=n;i++)vis[i]=0,d[i]=linf;
	queue<int>q;
	q.push(S),vis[S]=1,d[S]=0;
	while(q.size()){
		int u=q.front();vis[u]=0,q.pop();
		for(int i=h[u];i!=-1;i=e[i].nxt){
			if(d[u]+e[i].w<d[v]&&e[i].c>0){
				d[v]=d[u]+e[i].w;
				if(!vis[v])vis[v]=1,q.push(v);
			}
		}
	}
	return d[T]!=linf;
}
ll dfs(int x,ll fl){
	if(!fl||x==T)return fl;
	ll an=0,ss;vis[x]=1;
	for(int i=cur[x];i!=-1&&fl;i=e[i].nxt){
		cur[x]=i;
		if(d[x]+e[i].w==d[v]&&e[i].c>0&&!vis[v]){
			ss=dfs(v,min(fl,e[i].c));
			fl-=ss,an+=ss,mc+=(ss*e[i].w),e[i].c-=ss,e[i^1].c+=ss;
		}
	}
	vis[x]=0;//其实这句有没有都一样,没有的话常数还会略小些
	if(!an)cur[x]=-1;
	return an;
}
void mcDinic(){
	while(SPFA()){
		for(int i=0;i<=n;i++)cur[i]=h[i];
		mf+=dfs(S,linf);
	}
}
int main(){
	memset(h,-1,sizeof(h));
	while(m--){
		int o1=read(),o2=read(),o3=read(),o4=read();
		add(o1,o2,o3,o4),add(o2,o1,0,-o4);
	}
	mcDinic();
	write(mf),putchar(32),write(mc);
    return 0;
}

数据结构:

树状数组(我也是无语了,这种东西我还会忘):

int lowbit(int x){return x&(-x);}
void Plus(int i,int x){for(;i<=n;i+=lowbit(i))c[i]+=x;}
int sum(int i,int x){for(;i;i-=lowbit(i))x+=c[i];return x;}
//区间修改单点查询就用树状数组维护差分数组

主席树:

struct pst{
    int rt[1000005],val[25000005],lc[25000005],rc[25000005],num;
    void build(int &o,int l,int r){
        o=++num;if(l==r){val[o]=a[l];return;}
        int mid=l+r>>1;build(lc[o],l,mid),build(rc[o],mid+1,r);
    }
    void Update(int &o,int _pre,int l,int r,int x,int V){
        o=++num,lc[o]=lc[_pre],rc[o]=rc[_pre],val[o]=val[_pre];if(l==r){val[o]=V;return;}//本题val值可不加。
        int mid=l+r>>1;
        if(mid>=x)Update(lc[o],lc[_pre],l,mid,x,V);else Update(rc[o],rc[_pre],mid+1,r,x,V);
    }
    int query(int o,int l,int r,int x){
        if(l==r)return val[o];
        int mid=l+r>>1;
        if(mid>=x)return query(lc[o],l,mid,x);else return query(rc[o],mid+1,r,x);
    }
}A;

利用主席树查询静态区间第 \(k\) 小:

//luogu P3834
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,n2,m,cnt,a[200005],b[200005];
struct node{int sum,num,lc,rc;}A[5000005];
int bd(int l,int r){
    int fj=++cnt;
    if(l<r) A[fj].lc=bd(l,l+r>>1),A[fj].rc=bd((l+r>>1)+1,r);
    return fj;
}
void update(int &rt,int pre,int l,int r,int v){
    rt=++cnt,A[rt]=A[pre],A[rt].num++;
    if(l==r)return;
    int mid=l+r>>1;
    if(v<=mid)update(A[rt].lc,A[pre].lc,l,mid,v);
    else update(A[rt].rc,A[pre].rc,mid+1,r,v);
}
int query(int l,int r,int L,int R,int v){
    if(L>=R)return L;
    int x=A[A[r].lc].num-A[A[l].lc].num,mid=L+R>>1;
    if(x>=v)return query(A[l].lc,A[r].lc,L,mid,v);
    else return query(A[l].rc,A[r].rc,mid+1,R,v-x);
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0),cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
    sort(b+1,b+1+n),n2=unique(b+1,b+1+n)-b-1,A[0].sum=bd(1,n2);
    for(int i=1;i<=n;i++){
        int op=lower_bound(b+1,b+1+n2,a[i])-b;
        update(A[i].sum,A[i-1].sum,1,n2,op);
    }
    while(m--){
        int l,r,k;
        cin>>l>>r>>k;
        cout<<b[query(A[l-1].sum,A[r].sum,1,n2,k)]<<endl;
    }
	return 0;
}

重链剖分(不知道这算不算数据结构):

struct exst{
    ll dfn[50005],de[50005],fa[50005],wson[50005],s[50005],tp[50005],sum[200005],tag[200005],num;
    inline void dfs1(int x,int F){
        fa[x]=F,s[x]=1;
        for(int i=h[x];i!=-1;i=e[i].nxt){
            de[v]=de[x]+1,dfs1(v,x),s[x]+=s[v];
            if(s[v]>s[wson[x]])wson[x]=v;
        }
    }
    inline void dfs2(int x,int F){
        tp[x]=F,dfn[x]=++num;
        if(wson[x]!=50003)dfs2(wson[x],F);//本题结点编号从零开始,从一开始改一下即可
        for(int i=h[x];i!=-1;i=e[i].nxt)
            if(v!=wson[x])dfs2(v,v);
    }
    inline void pushup(int o){sum[o]=sum[o<<1]+sum[o<<1|1];}
    inline void pushdown(int o,int lc,int rc){tag[o<<1]+=tag[o],tag[o<<1|1]+=tag[o],sum[o<<1]+=lc*tag[o],sum[o<<1|1]+=rc*tag[o],tag[o]=0;}
    inline void Update(int o,int l,int r,int x,int y){
        if(l>=x&&r<=y){sum[o]+=(r-l+1),tag[o]++;return;}
        int mid=l+r>>1;
        if(tag[o])pushdown(o,mid-l+1,r-mid);
        if(mid>=x)Update(o<<1,l,mid,x,y);
        if(mid<y)Update(o<<1|1,mid+1,r,x,y);
        pushup(o);
    }
    inline ll query(int o,int l,int r,int x,int y){
        if(l>=x&&r<=y)return sum[o];
        int mid=l+r>>1;ll an=0;
        if(tag[o])pushdown(o,mid-l+1,r-mid);
        if(mid>=x)an+=query(o<<1,l,mid,x,y);
        if(mid<y)an+=query(o<<1|1,mid+1,r,x,y);
        return an;
    }
    inline void Upd(int o1,int o2){
        while(tp[o1]!=tp[o2]){
            if(de[tp[o1]]<de[tp[o2]])swap(o1,o2);
            Update(1,1,n,dfn[tp[o1]],dfn[o1]);
            o1=fa[tp[o1]];
        }
        if(de[o1]<de[o2])swap(o1,o2);
        Update(1,1,n,dfn[o2],dfn[o1]);
    }
    inline ll que(int o1,int o2){
        ll an=0;
        while(tp[o1]!=tp[o2]){
            if(de[tp[o1]]<de[tp[o2]])swap(o1,o2);
            an+=query(1,1,n,dfn[tp[o1]],dfn[o1]);
            o1=fa[tp[o1]];
        }
        if(de[o1]<de[o2])swap(o1,o2);
        an+=query(1,1,n,dfn[o2],dfn[o1]);
        return an;
    }
    void solve(){//填入题目需要实现的东西
        dfs1(0,-1),dfs2(0,-1);
        for(int i=1,j,k,l;i<=m;i++)j=read(),k=read(),l=read(),a[++at]={i,j-1,l,0},a[++at]={i,k,l,1};
        sort(a+1,a+1+at,cmp);
        for(int i=1,j=-1;i<=at;i++){
            if(a[i]._r==-1){ans[a[i].id][a[i].ki]=0;continue;}
            for(int k=j+1;k<=a[i]._r;k++)Upd(0,k);
            j=a[i]._r;
            ans[a[i].id][a[i].ki]=que(0,a[i].z);
        }
        for(int i=1;i<=m;i++)write((ans[i][1]-ans[i][0]+mod)%mod),putchar('\n');
    }
}A;

01trie 各种操作:

//luogu P6018
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
#define v e[i].y
using namespace std;
inline int read(){
    char ch=getchar();int x=0,w=1;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();return x*w;
}
inline void write(int x){
	if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
int n=read(),m=read(),cnt,tag[500005],h[500005],V[500005],fa[500005];struct node{int y,nxt;}e[1000005];
struct trie{
    int rt[500005],xorv[15000005],w[15000005],ch[15000005][2],tot=0;
    void maintain(int o){//类似线段树的 pushup
        w[o]=xorv[o]=0;
        if(ch[o][0])w[o]+=w[ch[o][0]],xorv[o]^=(xorv[ch[o][0]]<<1);
        if(ch[o][1])w[o]+=w[ch[o][1]],xorv[o]^=(xorv[ch[o][1]]<<1)|(w[ch[o][1]]&1);
    }
    inline int mknode(){tot++,ch[tot][0]=ch[tot][1]=w[tot]=0;return tot;}//新建结点
    void Insert(int &o,int x,int dp){//在某结点下插入一条链(即增加一个数,注意要在它父亲结点插)
        if(!o)o=mknode();if(dp>20)return (void)(w[o]++);//若大于最大深度返回并标记该结点
        Insert(ch[o][x&1],x>>1,dp+1),maintain(o);
    }
    void Erase(int o,int x,int dp){if(dp>20)return (void)(w[o]--);Erase(ch[o][x&1],x>>1,dp+1);maintain(o);}//删除一个数,注意也要从父亲结点删
    void addall(int o){swap(ch[o][1],ch[o][0]);if(ch[o][0])addall(ch[o][0]);maintain(o);}//全局加一
    void dfs0(int x,int f){fa[x]=f;for(int i=h[x];i!=-1;i=e[i].nxt)if(v!=f)dfs0(v,x);}
    //其实还少一个 trie 树合并操作,与线段树合并类似
}A;
void add(int o1,int o2){e[cnt].nxt=h[o1],e[cnt].y=o2,h[o1]=cnt++;}
inline int Get(int x){return (fa[x]==-1?0:tag[fa[x]])+V[x];}//爹的标记才是真正的标记,因为自己记的都是儿子的
signed main(){
    memset(h,-1,sizeof(h));for(int i=1,j,k;i<n;i++)j=read(),k=read(),add(j,k),add(k,j);A.dfs0(1,-1);
    for(int i=1;i<=n;i++){V[i]=read();if(fa[i]!=-1)A.Insert(A.rt[fa[i]],V[i],0);}
    while(m--){
        int o1=read(),o2=read();
        if(o1==1){//此操作为将某节点附近所有距离为一的结点加一
            tag[o2]++;//打tag,因为之后的全局加仅改变该点异或和,没彻底完成操作,把加一遗留到儿子
            if(o2!=1){
                if(fa[fa[o2]]!=-1)A.Erase(A.rt[fa[fa[o2]]],Get(fa[o2]),0);
                V[fa[o2]]++;
                if(fa[fa[o2]]!=-1)A.Insert(A.rt[fa[fa[o2]]],Get(fa[o2]),0);
            }//此处 fa 数组有些绕,是重点,需仔细理解
            A.addall(A.rt[o2]);
        }
        if(o1==2){//把某节点权值减定值,即先删后插改变的权值
            int yu=read();
            if(o2!=1)A.Erase(A.rt[fa[o2]],Get(o2),0);V[o2]-=yu;
            if(o2!=1)A.Insert(A.rt[fa[o2]],Get(o2),0);
        }
        if(o1==3)write(A.xorv[A.rt[o2]]^Get(fa[o2])),puts("");//访问某节点距离为一的所有结点异或和,即以它为根子树异或它爹的
    }
	return 0;
}

各类平衡树(放的都是洛谷P3369的代码):

有旋 treap(速度比 splay 快,但不支持区间):

#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define INF 0x3f
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-48,ch=getchar();return w==1?x:-x;
}
inline void write(ll x){
	if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
int n=read();
struct rotreap{
    int num,rt;
    struct Node{int ch[2],rd,val,si,cnt;}a[100005];
    void pushup(int x){a[x].si=a[a[x].ch[0]].si+a[a[x].ch[1]].si+a[x].cnt;}
    void Rotate(int &x,int d){//仅insert和erase需要旋转
        int son=a[x].ch[d];
        a[x].ch[d]=a[son].ch[d^1],a[son].ch[d^1]=x;
        pushup(x),pushup(x=son);
    }
    void Insert(int &x,int V){
        if(!x){x=++num,a[x].rd=rand(),a[x].val=V,a[x].si=a[x].cnt=1;return;}
        a[x].si++;
        if(V==a[x].val){a[x].cnt++;return;}
        int d=(V>a[x].val);
        Insert(a[x].ch[d],V);
        if(a[a[x].ch[d]].rd<a[x].rd)Rotate(x,d);
    }
    void Erase(int &x,int V){//最容易错的部分啦
        if(!x)return;
        if(V==a[x].val){
            if(a[x].cnt>1){a[x].si--,a[x].cnt--;return;}
            if(!a[x].ch[0]||!a[x].ch[1]){x=a[x].ch[0]+a[x].ch[1];return;}
            int d=(a[a[x].ch[0]].rd>a[a[x].ch[1]].rd);
            Rotate(x,d),Erase(x,V);
            return;
        }
        a[x].si--;
        int d=(V>a[x].val);
        Erase(a[x].ch[d],V);
    }
    int quev(int x,int V){
        if(!x)return 0;
        if(a[x].val==V)return a[a[x].ch[0]].si+1;
        if(a[x].val<V)return a[a[x].ch[0]].si+a[x].cnt+quev(a[x].ch[1],V);
        if(a[x].val>V)return quev(a[x].ch[0],V);
    }
    int quek(int x,int k){
        if(!x)return inf;
        if(k<=a[a[x].ch[0]].si)return quek(a[x].ch[0],k);
        if(k<=a[a[x].ch[0]].si+a[x].cnt)return a[x].val;
        return quek(a[x].ch[1],k-a[a[x].ch[0]].si-a[x].cnt);
    }
    int quep(int x,int V){
        if(!x)return -inf;
        if(V<=a[x].val)return quep(a[x].ch[0],V);
        return max(quep(a[x].ch[1],V),a[x].val);
    }
    int quen(int x,int V){
        if(!x)return inf;
        if(V>=a[x].val)return quen(a[x].ch[1],V);
        return min(quen(a[x].ch[0],V),a[x].val);
    }
}A;
int main(){
    while(n--){
        int opt=read(),x=read();
        if(opt==1)A.Insert(A.rt,x);
        if(opt==2)A.Erase(A.rt,x);
        if(opt==3)write(A.quev(A.rt,x));
        if(opt==4)write(A.quek(A.rt,x));
        if(opt==5)write(A.quep(A.rt,x));
        if(opt==6)write(A.quen(A.rt,x));
        if(opt>=3)putchar('\n');
    }
    return 0;
}

无旋 treap(非常实用,容易打,速度不比有旋慢多少,普通 treap 和 splay 的操作都能完成,可基本替代有旋 treap 和 splay):

//luogu P3369
#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define INF 0x3f
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-48,ch=getchar();return w==1?x:-x;
}
inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
int n=read();
struct fhqtreap{
    #define lc ch[o][0]
    #define rc ch[o][1]
    int ch[100005][2],si[100005],rd[100005],val[100005],rt,num,r1,r2,r3;
    int newnode(int V){num++,si[num]=1,rd[num]=rand(),val[num]=V;return num;}
    void pushup(int o){si[o]=si[lc]+si[rc]+1;}
    void Split(int o,int V,int &A,int &B){//这个最容易写错
        if(!o){A=B=0;return;}
        if(V>=val[o])A=o,Split(rc,V,rc,B);
        else B=o,Split(lc,V,A,lc);
        pushup(o);
    }
    int Merge(int A,int B){
        if(!A||!B)return A+B;
        if(rd[A]<rd[B]){ch[A][1]=Merge(ch[A][1],B),pushup(A);return A;}
        else{ch[B][0]=Merge(A,ch[B][0]),pushup(B);return B;}
    }
    void Insert(int V){
        r1=r2=r3=0;
        Split(rt,V,r1,r2);
        rt=Merge(Merge(r1,newnode(V)),r2);
    }
    void Erase(int V){
        r1=r2=r3=0;
        Split(rt,V,r1,r3),Split(r1,V-1,r1,r2);
        rt=Merge(Merge(r1,Merge(ch[r2][0],ch[r2][1])),r3);
    }
    int queV(int V){
        r1=r2=r3=0;
        Split(rt,V-1,r1,r2);
        int ans=si[r1]+1;
        rt=Merge(r1,r2);
        return ans;
    }
    int quek(int R,int k){
        while(1){
            if(k<=si[ch[R][0]])R=ch[R][0];
            else if(si[ch[R][0]]+1==k)return R;
            else k-=(si[ch[R][0]]+1),R=ch[R][1];
        }
    }
    int pre(int V){
        r1=r2=r3=0;
        Split(rt,V-1,r1,r2);
        int ans=val[quek(r1,si[r1])];
        rt=Merge(r1,r2);
        return ans;
    }
    int nxt(int V){
        r1=r2=r3=0;
        Split(rt,V,r1,r2);
        int ans=val[quek(r2,1)];
        rt=Merge(r1,r2);
        return ans;
    }
    void solve(){
        int opt,x;
        while(n--){
            opt=read(),x=read();
            if(opt==1)Insert(x);
            if(opt==2)Erase(x);
            if(opt==3)write(queV(x));
            if(opt==4)write(val[quek(rt,x)]);
            if(opt==5)write(pre(x));
            if(opt==6)write(nxt(x));
            if(opt>=3)putchar('\n');
        }
    }
}A;
int main(){
    A.solve();   
    return 0;
}

splay(支持区间,但速度慢):

暂时不会

替罪羊树(听说速度很不错?):

//替罪羊树
//debug:rebuild函数未把结点信息重置,实际上应该对于每个结点都重置结点信息(尤其是左右儿子应该置为0)
#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define INF 0x3f
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-48,ch=getchar();return w==1?x:-x;
}
inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
struct ScapegoatTree{
    int n,m,cnt,rt,aa,ans,lans;
    double alpha;
    int a[1500050],s[1500000],sw[1500005],sd[1500005],wn[1500006],Val[1500006],ls[1500050],rs[1500000];
    void pushup(int o){
        s[o]=s[ls[o]]+s[rs[o]]+1;
        sw[o]=sw[ls[o]]+sw[rs[o]]+wn[o];
        sd[o]=sd[ls[o]]+sd[rs[o]]+(wn[o]!=0);
    }
    bool pdre(int o){return s[o]*alpha<max(s[ls[o]],s[rs[o]])||sd[o]<s[o]*alpha;}
    void df(int o){
        if(!o)return;
        df(ls[o]);
        if(wn[o])a[++aa]=o;
        df(rs[o]);
    }
    void rebuild(int &o,int l,int r){
        if(l>r)return;
        if(l==r){o=a[l],s[o]=sd[o]=1,sw[o]=wn[o],ls[o]=rs[o]=0;return;}
        int mid=l+r>>1;
        o=a[mid],ls[o]=rs[o]=0,rebuild(ls[o],l,mid-1),rebuild(rs[o],mid+1,r);
        pushup(o);
    }
    void bd(int &o){aa=0,df(o),rebuild(o,1,aa);}
    void Insert(int &o,int V){
        if(!o){o=++cnt,s[o]=sw[o]=sd[o]=wn[o]=1,Val[o]=V;return;}
        if(V==Val[o])wn[o]++;
        else if(V<Val[o])Insert(ls[o],V);
        else Insert(rs[o],V);
        pushup(o);
        if(pdre(o))bd(o);
    }
    void Erase(int &o,int V){
        if(!o)return;
        if(V==Val[o])wn[o]--;
        else if(V<Val[o])Erase(ls[o],V);
        else Erase(rs[o],V);
        pushup(o);
        if(pdre(o))bd(o);
    }
    int queV(int o,int V){
        int an=1;
        //cout<<endl;
        while(o){
          //  cout<<Val[o]<<" "<<Val[ls[o]]<<" "<<Val[rs[o]]<<" "<<V<<" "<<an<<endl;
            if(V<Val[o])o=ls[o];
            else if(V==Val[o]){an+=sw[ls[o]];break;}
            else an+=sw[ls[o]]+wn[o],o=rs[o];
        }
        return an;
    }
    int quek(int o,int k){
        //cout<<endl;
        while(1){
           //cout<<k<<" "<<sw[o]<<" "<<sw[ls[o]]<<" "<<sw[rs[o]]<<endl;
            if(k<=sw[ls[o]])o=ls[o];
            else if(k<=sw[ls[o]]+wn[o])return Val[o];
            else k-=(sw[ls[o]]+wn[o]),o=rs[o];
        }
    }
    int pre(int V){return quek(rt,queV(rt,V)-1);}
    int nxt(int V){return quek(rt,queV(rt,V+1));}
    void solve(){
        n=read(),m=read(),rt=cnt=1,alpha=0.7;
        for(int i=1,j;i<=n;i++)j=read(),Insert(rt,j);
        int o1,o2;
        while(m--){
            o1=read(),o2=read(),o2^=lans;
            //cout<<"*"<<o1<<" "<<o2<<"*"<<endl;
            if(o1==1)Insert(rt,o2);
            if(o1==2)Erase(rt,o2);
            if(o1==3)lans=queV(rt,o2);
            if(o1==4)lans=quek(rt,o2);
            if(o1==5)lans=pre(o2);
            if(o1==6)lans=nxt(o2);
            if(o1>=3)ans^=lans;
            //cout<<lans<<endl;
        }
        write(ans);
    }
}T;
int main(){
    T.solve();   
    return 0;
}

AVL(优缺点??):

暂时不会

红黑树(听说效率极快,但码量巨大,很复杂,stl 就是用它实现的?):

肯定不会···

有用的玄学算法:

模拟退火(放了廊桥分配 60pts 和平衡点的正解代码):

void SA(){
    double T=1,delta=0.9;//随意调参,T是初始温度,一般会有一千以上,本题例外,delta 是降温系数
    int X=ansx,nowx,deltaw;//x 是当前执行的点,ansx 是当前最优答案
    while(T>1e-18){
        if(tr==n+1)break;//本题我用的优化,不属于 SA 部分
        nowx=X+(rand()%(n+1)-X)*T;//随机弄出个点
        if(vis[nowx]){T*=0.99;continue;}
        if(sum1[nowx]==-1)pd1(nowx);
        if(sum2[n-nowx]==-1)pd2(n-nowx);
        deltaw=sum1[nowx]+sum2[n-nowx]-ans;//计算出当前点的解
        if(deltaw>0)ans+=deltaw,ansx=X=nowx;//如果更优就取
        else if(exp(deltaw/1.0/T)+RAND_MAX>rand())X=nowx;//不更优用一定概率取
        T*=delta,tr++,vis[nowx]=1;
    }
}
//标准的 SA 来了,(平衡点代码)
void SA(){
    double delta=0.99,T=1000,deltaw,nowx=ansx,nowy=ansx,X=ansx,Y=ansy,len;
    while(T>1e-18){
        deltaw=0,nowx=X+(rand()*2-RAND_MAX)*T,nowy=Y+(rand()*2-RAND_MAX)*T;
        for(int i=1;i<=n;i++){
            len=sqrt((nowx-a[i])*(nowx-a[i])+(nowy-b[i])*(nowy-b[i]));
            deltaw+=len*w[i];
        }
        if(deltaw<ans)ans=deltaw,ansx=nowx,ansy=nowy,X=nowx,Y=nowy;
        else if(exp((ans-deltaw)/T)*RAND_MAX>rand())X=nowx,Y=nowy;
        T*=delta,ansti+=n;
    }
}

爬山:

//不要模拟退火更换更劣解的一行就成了爬山QWQ
posted @ 2022-07-24 12:23  mcDinic  阅读(21)  评论(0)    收藏  举报