自用模板积累(持续更新)

前言

命名规则

t: (全局)test cases测试组数/
(局部)temp 临时变量
sum: 和/前缀和
n: 序列长度 pre: previous 指向时间戳小的/后驱
m: 子序列长度 nxt: next 指向时间戳大的/前驱
len: length 字符串长度 s/e: start/end 开始/结束
cnt: count 计数 arr: array 序列
i/j/k…: 循环变量 s/t: 字符串/主串/模式串
idx: index 下标 m/mp: map 映射
p/q: position 指针 st: set 集合
l/r: left/right 左区间/右区间 stk: stack 栈
max/min: 最大/最小 que: queue 队列
vis: visite 是否访问 g: graph 图
sub: 差/差分 e/edge: 边
ans: answer 输出 v:verticle 结点
dis: distance 距离 inf: infinity 无穷大

顺序编号原则:a、b、c…
arra、arrb、arrc
命名冲突原则:重复末尾字母
字符串s、t,临时变量tt

常用预编译

//<iomanip><sstream><queue>
#define ll long long
#define rep(i,a,b) for(ll i=a;i<b;++i)//0开始
#define rev(i,a,b) for(ll i=a-1;i>=b;--i)
#define reb(i,a,b) for(ll i=a+1;i<b+1;++i)//1开始
#define red(i,a,b) for(ll i=a;i>b;--i)
#define inf 0x3f3f3f3f
#define clr(arr,val) memset(arr,val,sizeof arr)
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mid ((l+r)>>1)
#define sonl rt<<1,l,mid
#define sonr rt<<1|1,mid+1,r
#define tinfo ll rt,ll l,ll 

零散技巧

31-__builtin_clz(n);//取对数
__builtin_popcount(n);//二进制1的个数

基础算法

快速排序

void qsort(ll l,ll r)
{
   
  if(l>=r) return;
  ll val=arr[l],p=l,q=r;
  while(p<q)
  {
   
    while(p<q&&arr[q]>val) q--;
    if(p<q){
   arr[p]=arr[q];p++;}
    while(p<q&&arr[p]<val) p++;
    if(p<q){
   arr[q]=arr[p];q--;}
  }
  arr[p]=val;
  qsort(l,p-1);
  //if(m-1>p) 求第m小数
  qsort(p+1,r);
}

并查集

rep(i,0,n) pre[i]=i;//********WARNING*********

无权+状态压缩

ll find(ll x){
   return x==pre[fx]?x:(pre[x]=find(pre[x]));}
void unionn(ll u,ll v){
   pre[find(u)]=find(v);}

带权+状态压缩

ll find(ll x) {
   
  if(x==pre[x]) return x;
  ll fx=pre[x];
  pre[x]=find(pre[x]);
  val[x]+=val[fx];
  return pre[t];
}
void unionn(ll a,ll b,ll value) {
   
  ll fa=pre[a],fb=pre[b];
  val[fa]=val[b]+value-val[a];
  pre[fa]=fb;
}

高精度(输入均为逆序字符串)

加/乘 通用模板(记得修改成带返回值得)

void [add@mult](char aa[],char bb[]) {
   
  int a[maxn],b[maxn],c[maxn];
  clr(a,0);clr(b,0);clr(c,0);
  int cnta=strlen(aa),cntb=strlen(bb),cntc=[max(cnta,cntb)+1@cnta+cntb+1];
  rep(i,0,cnta) a[i]=aa[i]-'0';
  rep(i,0,cntb) b[i]=bb[i]-'0';
  [rep(i,0,cntc) c[i]=a[i]+b[i];@
  rep(i,0,cnta) rep(j,0,cntb) c[i+j]+=a[i]*b[j];]
  ll t=0;
  rep(i,0,cntc) {
   
    c[i]+=t;
    t=c[i]/10;
    c[i]%=10;
  }
  while(c[cntc]==0) cntc--;
  rep(i,0,cntc+1) cc[i]=c[i]+'0';
  cc[cntc+1]=0;
}

字符串

kmp

int j=pre[0]=-1,k=0;
//pre[i]为i位置(右开)最长公共前后缀
while(k<lent){
   
    while(j!=-1&&t[j]!=t[k]) j=pre[j];
    pre[++k]=++j;
    //if(t[++j]==t[++k]) pre[k]=pre[j]; 优化
    //else pre[k]=j;
}

j=k=0;
while(k<lens){
   
    while(j!=-1&&s[k]!=t[j]) j=pre[j];
    j++;k++;
    if(j==lent)
    {
   
    	cnt++;
    	j=pre[j];//重叠
    	//j=0;//不重叠
    }
}
if(j==lent) printf("%d\n",k-m+1);
//lent-nxt[lent]//最小循环节长度

manacher

char s[maxn];
char ma[maxn*2];
int mp[maxn*2];
int id,mx,n,len;
void manacher() {
   
  len=0;
  ma[len++]='!';
  ma[len++]='?';
  rep(i,0,n) {
   
    ma[len++]=s[i];
    ma[len++]='?';
  }
  id=mx=0;
  rep(i,0,len) {
   
    mp[i]=mx>i?min(mp[2*id-i],mx-i):1;
    while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
    if(i+mp[i]>mx) {
   
      id=i;
      mx=i+mp[i];
    }
  }
}

  while(scanf("%s",s)==1) {
   
    n=strlen(s);
    manacher();
    int maxlen=1;
    for(int i=0; i<len; i++) maxlen=max(maxlen,mp[i]-1);
    //长度:mp[i]-1//起始位置:(i-mp[i])>>1
    printf("%d\n",maxlen);
  }

图论

二分图最大匹配(Hungary)

int n,m,k;
bool g[maxn][maxn],vis[maxn];
int lnk[maxn];

bool dfs(int u) {
    //可否更改
  rep(i,0,m) {
   
    if(g[u][i]&&!vis[i]) {
   
      vis[i]=true;
      if(lnk[i]==-1||dfs(lnk[i])) {
   
        lnk[i]=u;
        return true;
      }
    }
  }
  return false;
}

  int ans=0;
  memset(lnk,-1,m*sizeof(int));
  rep(i,0,n) {
   
    memset(vis,0,m*sizeof(bool));
    if(dfs(i)) ans++;
  }
  return ans;

最短路径

Dij

邻接矩阵

ll n,s,e;
ll dis[maxn],g[maxn][maxn];
bool vis[maxn];
//g[ta][tb]=g[tb][ta]=min(g[ta][tb],tc);
  dis[s]=0;
  while(s!=e)
  {
   
    ll mindis=inf,idx;
    vis[s]=true;
    rep(i,0,n)
    {
   
      dis[i]=min(dis[i],dis[s]+g[s][i]);
      if(!vis[i]&&dis[i]<mindis) mindis=dis[idx=i];
    }
    if(mindis==inf) break;
    s=idx;
  }
  cout<<dis[e]<<endl;

堆优化+前向星

ll n,m;
ll dis[maxn],hd[maxn];
bool vis[maxn];
ll cnt;
ll to[maxm],w[maxm],nxt[maxm];
ll ta,tb,tc,s,e;
struct node {
   
  ll s,w;
  bool operator<(const node &a)const {
   
    return a.w<w; //与condition()同步
  }
};
priority_queue<node> que;

  //init
  memset(dis,inf,sizeof dis);
  memset(vis,0,sizeof vis);
  memset(hd,0,sizeof hd)//*******WARNING********
  cnt=0;
  //in
  cin>>n>>m;
  rep(i,0,m) {
   
    cin>>ta>>tb>>tc;

    w[++cnt]=tc;
    to[cnt]=tb;
    nxt[cnt]=hd[ta];
    hd[ta]=cnt;
  }
  cin>>s>>e;
  //dij
  dis[s]=0;
  que.push(node{
   s,0});
  while(!que.empty()) {
   
    node t=que.top();
    que.pop();
    if(vis[t.s]) continue;
    vis[t.s]=true;
    for(ll i=hd[t.s]; i; i=nxt[i]) {
   
      if(dis[t.s]+w[i]<dis[to[i]])
        //if(condition(stucture(dis[pnt],w[i]),dis[to[i]])) <条件>的<结构> ex. min(dis[pnt],w[i])>dis[to[i]] 最大的路径的边的最小值
      {
   
        dis[to[i]]=dis[t.s]+w[i];
        que.push(node{
   to[i],dis[to[i]]});
      }
    }
  }
  //out
  cout<<dis[e]<<endl;

双向链表遍历

ll n,m;
vector<ll> nxt[maxn];
bool vis[maxn];
ll ans;
void dfs(ll p) {
   
  if(vis[p]) return;
  vis[p]=true;
  bool found=false;//有无子节点
  rep(j,0,nxt[p].size()) {
   
    if(!vis[nxt[p][j]]) found=true;
    dfs(nxt[p][j]);
  }
  if(!found) ans++;
}
  scanf("%lld%lld",&n);
  rep(i,0,n-1) {
   
    ll ta,tb;
    scanf("%lld%lld",&ta,&tb);
    nxt[ta].push_back(tb);
    nxt[tb].push_back(ta);
  }
  dfs(1);
  printf("%lld\n",ans);

二叉树

先序遍历+中序遍历->后序遍历(dfs)

int n;
int pre[maxn];
int in[maxn];
bool head;
void build(int la,int ra,int lb,int rb) {
   
  if(la==ra) return;
  if(la+1==ra) {
   
    if(head) {
   
      printf("%d",pre[la]);
      head=false;
    } else printf(" %d",pre[la]);
    return;
  }
  int p=lb;
  while(in[p]!=pre[la]&&p<rb)p++;
  build(la+1,la+1+p-lb,lb,p);
  build(la+1+p-lb,ra,p+1,rb);
  if(head) {
   
    printf("%d",pre[la]);
    head=false;
  } else printf(" %d",pre[la]);
}

  while(~scanf("%d",&n)) {
   
    head=true;
    rep(i,0,n) scanf("%d",&pre[i]);
    rep(i,0,n) scanf("%d",&in[i]);
    build(0,n,0,n);
    puts("");
  }

查询/修改

树状数组

ll tree[maxn];

ll lowbit(int x) {
   
  return x&(-x);
}
void update(ll x) {
   
  while(x<=n) {
   
    tree[x]++;
    x+=lowbit(x);
  }
}
ll getsum(ll x) {
   
  ll ans=0;
  while(x) {
   
    ans+=tree[x];
    x-=lowbit(x);
  }
  return ans;
}
ll qury(ll l,ll r) {
   
  return getsum(r)-getsum(l-1);
}

线段树

ll tree[maxn<<2];
ll arr[maxn];
ll n;
void pushup(ll rt) {
   
  //要维护操作
  tree[rt]=operation(tree[rt<<1],tree[rt<<1|1]);
}
void build(tinfo) {
   
  if(l==r) {
   
    tree[rt]=arr[l];
    return;
  }
  build(sonl);
  build(sonr);
  pushup(rt);
}
void update(tinfo,ll p,ll w) {
   
  if(l==r) {
   
  	//更新操作
    tree[rt] operation=w;
    return ;
  } else if(p>mid) update(sonr,p,w);
  else update(sonl,p,w);
  pushup(rt);
}
ll qury(ll p,ll l,ll r,ll tl,ll tr) {
   
  if(tl<=l&&tr>=r) return tree[rt];
  ll ans;
  if(tr>mid) ans operation=qury(sonr,tl,tr);
  if(tl<=mid) ans operation=qury(sonl,tl,tr);
  return ans;
}

RMQ(ST)

ll n,q;
ll arr[maxn];
ll dp[20][maxn];
inline ll log(ll n) {
   
  return 31-__builtin_clz(n);
}
void prep() {
   
  rep(i,0,n)
  dp[0][i]=arr[i];
  ll logen=log(n);
  reb(i,0,logen)
  rep(j,0,n-(1<<i-1))
  dp[i][j]=max(dp[i-1][j],dp[i-1][j+(1<<i-1)]);
}
ll query(ll l,ll r) {
   
  ll logen=log(r-l);
  return max(dp[logen][l],dp[logen][r-(1<<logen)]);
}
  scanf("%lld%lld",&n,&q);
  rep(i,0,n)
  scanf("%lld",&arr[i]);
  prep();
  while(q--) {
   
// init();
    ll l,r;
    scanf("%lld%lld",&l,&r);
    printf("%lld\n",query(l-1,r);
  }
  return 0;
全部评论

相关推荐

点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务