面试前夕oi挣扎式复习

  • 线段树

void PushUp(ll rt){
    Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];
}
void Build(ll l,ll r,ll rt){
    if(l==r){
        Sum[rt]=A[l];
        return ;
    }
    ll m=(l+r)>>1;
    Build(l,m,rt<<1);
    Build(m+1,r,rt<<1|1);
    PushUp(rt);
}
void PushDown(ll rt,ll ln,ll rn){//下推标记 
    if(Add[rt]){
        Add[rt<<1]+=Add[rt];
        Add[rt<<1|1]+=Add[rt];
        Sum[rt<<1]+=Add[rt]*ln;
        Sum[rt<<1|1]+=Add[rt]*rn;
        Add[rt]=0;//清除标记 
    }
}
void Update(ll L,ll R,ll C,ll l,ll r,ll rt){//区间修改 
    if(L<=l&&r<=R){//如果[l,r]区间完全在操作区间[L,R]以内
        Sum[rt]+=C*(r-l+1);
        Add[rt]+=C;
        return ;
    }
    ll m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m);
    if(L<=m)Update(L,R,C,l,m,rt<<1);
    if(R>m) Update(L,R,C,m+1,r,rt<<1|1);
    PushUp(rt);
}
ll Query(ll L,ll R,ll l,ll r,ll rt){//区间求和 
    if(L<=l&&r<=R){//在区间内直接返回 
        return Sum[rt];
    }
    ll m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m);
    ll ANS=0;
    if(L<=m)ANS+=Query(L,R,l,m,rt<<1);
    if(R>m) ANS+=Query(L,R,m+1,r,rt<<1|1);
    return ANS;
}
  • 树状数组

inline ll lowbit(ll x) {return x&-x;}
inline void add(int x,ll k)
{
    while(x<=n)
    {
        a[x]+=k;x+=lowbit(x);
    }
}
inline ll find(int x)
{
    ll sum=0;
    while(x)
    {
        sum+=a[x];x-=lowbit(x);
    }
    return sum;
}
  • tarjan缩点

void dfs(int u)
{
    dfn[u]=low[u]=++tot;
    vis[u]=1;sta[++top]=u;
    for(int j=head[u];j;j=e[j].nxt)
    {
        int v=e[j].v;
        if(!dfn[v])
        {
            dfs(v);low[u]=min(low[u],low[v]);
        }
        else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        int x;
        while(1)
        {
            x=sta[top--];vis[x]=0;
            fa[x]=u;if(x==u)break;
            a[u]+=a[x];
        }
    }
}
  • 线性基

   for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        for(int k=62;k>=0;k--)if((1LL<<k)&x)
        {
            if(!xx[k]) {xx[k]=x;break;} 
            x^=xx[k];
        }
    }
    ll ans=0;
    for(int k=62;k>=0;k--) if((ans^xx[k])>ans) ans^=xx[k];
  • ST表

    lg[0]=-1;
    for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&f[0][i]);
    }
    for(int j=1;j<=20;j++) 
    for(int i=1;i+(1<<j)-1<=n;i++) f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
    int x,y,k;
    while(m--)
    {
        scanf("%d%d",&x,&y);
        k=lg[y-x+1];
        printf("%d\n",max(f[k][x],f[k][y-(1<<k)+1]));
    }    
  • 并查集

inline int get(int x) {return x==fa[x]?x:fa[x]=get(fa[x]);} 
  • 欧拉筛

void GetPrime(int n)//筛到n
{
    memset(isPrime, 1, sizeof(isPrime));
    //以“每个数都是素数”为初始状态,逐个删去
    isPrime[1] = 0;//1不是素数
    
    for(int i = 2; i <= n; i++)
    {
        if(isPrime[i])//没筛掉 
            Prime[++cnt] = i; //i成为下一个素数
            
        for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++) 
        {
            //从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
            //当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
            isPrime[i*Prime[j]] = 0;
            
            if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
                break; //重要步骤。见原理
        }
    }
}
  • 网络流最大流

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e4+50,M=1e5+50;
struct pp
{
    int v,nxt,c;
}e[M<<2];
int tot=1,n,m,st,ed;
int head[N],dep[N],gap[N];
void add(int u,int v,int c)
{
    e[++tot].nxt=head[u];head[u]=tot;
    e[tot].v=v;e[tot].c=c;
    e[++tot].nxt=head[v];head[v]=tot;
    e[tot].v=u;e[tot].c=0;
}
void bfs()
{
    memset(dep,-1,sizeof(dep));
    gap[dep[ed]=0]=1;
    queue<int> q;q.push(ed);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int j=head[u];j;j=e[j].nxt)
        {
            int v=e[j].v;
            if(dep[v]!=-1) continue;
            q.push(v);gap[dep[v]=dep[u]+1]++;
        }
    }
}
int dfs(int u,int flow)
{
    if(u==ed) return flow;
    int s=0,val;
    for(int j=head[u];j;j=e[j].nxt)
    {
        int v=e[j].v,c=e[j].c;
        if(c<=0||dep[v]!=dep[u]-1)continue;
        s+=(val=dfs(v,min(c,flow-s)));
        e[j].c-=val;e[j^1].c+=val;
        if(s==flow) return s;
    }
    gap[dep[u]]--;
    if(gap[dep[u]]==0) dep[st]=n+1;
    gap[++dep[u]]++;
    return s;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&st,&ed);
    for(int i=1,u,v,c;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&c);
        add(u,v,c);
    }
    bfs();
    int res=0;
    while(dep[st]<n) res+=dfs(st,233333333L);
    printf("%d\n",res);
    return 0;
}
  • 快速矩阵幂

struct Mat
{
    ll m[N][N];
    Mat operator = (int x)
    {
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 
        m[i][j]=(i==j&&x);    return *this;
    }
    Mat operator * (Mat b)
    {
        Mat a=*this,c;c=0;
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
        for(int k=1;k<=n;k++) (c.m[i][j]+=(a.m[i][k]*b.m[k][j]))%=MOD;
        return c;
    }
    Mat operator ^ (ll b)
    {
        Mat a=*this,c;c=1;
        for(;b;b>>=1) {if(b&1) c=c*a;a=a*a;} 
        return c;
    }
} d;
void print(Mat a)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)  printf("%lld ",a.m[i][j]);printf("\n");
    }
}
  • 最小费用最大流

#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5050,M=50050;
struct pp
{
    int v,nxt,d,c;
}e[M<<1];
int head[N],flow[N],tot=1,pre[N],dis[N];
bool vis[N];
int n,m,st,ed;
long long res,ans;
int min(int a,int b)
{
    return a>b?b:a;
}
void add(int u,int v,int c,int d)
{
    e[++tot].nxt=head[u];head[u]=tot;
    e[tot].v=v;e[tot].d=d;e[tot].c=c;
    e[++tot].nxt=head[v];head[v]=tot;
    e[tot].v=u;e[tot].d=-d;e[tot].c=0;
}
bool spfa()
{
    queue<int> q;q.push(st);
    memset(dis,0x3f,sizeof(dis));
    dis[st]=0;flow[st]=233333333L;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(int j=head[u];j;j=e[j].nxt)
        {
            int v=e[j].v,c=e[j].c,d=e[j].d;
            if(c<=0) continue;
            if(dis[v]>dis[u]+d)
            {
                dis[v]=dis[u]+d;
                pre[v]=j;
                flow[v]=min(flow[u],c);
                if(!vis[v])
                    vis[v]=1,q.push(v);
            }
        }
    }
    if(dis[ed]==dis[0]) return 0;
    int mn=233333333L;
    for(int x=ed,j;x!=st;x=e[j^1].v)
        j=pre[x],mn=min(mn,flow[x]);
    res+=1LL*mn*dis[ed];
    ans+=1LL*mn;
    for(int x=ed,j;x!=st;x=e[j^1].v)
    {
        j=pre[x];
        e[j].c-=mn;
        e[j^1].c+=mn;
    }
    return 1;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&st,&ed);
    for(int i=1;i<=m;i++)
    {
        int u,v,c,d;
        scanf("%d%d%d%d",&u,&v,&c,&d);
        add(u,v,c,d);
    }
    while(spfa());
    printf("%lld %lld\n",ans,res);
    return 0;
}
  • 最近公共祖先LCA

void dfs(int u,int la)
{
    f[u][0]=la;dep[u]=dep[la]+1;
    for(int i=1;i<=lg[dep[u]];i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int j=head[u];j;j=e[j].nxt)
    {
        int v=e[j].v;
        if(v==la) continue;
        dfs(v,u);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) x^=y^=x^=y;
    while(dep[x]>dep[y])
        x=f[x][lg[dep[x]-dep[y]-1]];
    if(x==y) return x;
    for(int k=lg[dep[x]];k>=0;k--)
        if(f[x][k]!=f[y][k])
            x=f[x][k],y=f[y][k];
    return f[x][0];
}
  • dijkstra

void dijkstra()
{
    memset(dis,127/3,sizeof(dis));
    dis[s]=0;
    q.push((qq){s,0});
    while(!q.empty())
    {
        qq x=q.top();q.pop();
        int u=x.u;
        if(vis[u]) continue;
        vis[u]=1;
        for(int j=head[u];j;j=e[j].nxt)
        {
            int v=e[j].to,d=e[j].d;
            if(dis[v]>dis[u]+d)
            {
                dis[v]=dis[u]+d;
                q.push((qq){v,dis[v]});
            }
        }
    }
}
  • spfa

void spfa()
{
  queue<int> q; //spfa用队列,这里用了STL的标准队列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //带权图初始化
    vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
  }
  q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
  while(!q.empty())
  {
    int u=q.front(); //取出队首
    q.pop(); vis[u]=0; //出队标记
    for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入队则入队
        {
          vis[v]=1; //标记入队
          q.push(v);
        }
      }
    }
  }
}
  • 二分图匹配

bool Dfs(int u,int t)  // t为时间戳  
{
    for(int j=head[u];j;j=e[j].nxt)
    {
        int v=e[j].v;
        if(vis[v]^t) // 要是 vis 和 t 不相等说明本次 dfs 还没用到 v  
        {
            vis[v]=t;
            if((!f[v])||Dfs(f[v],t))
            {
                f[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
  • exgcd

void exgcd(ll a, ll b, ll& x, ll& y, ll& c)
{
     if(!b) {y = 0; x = 1; c = a; return;}
     exgcd(b, a % b, y, x); y -= a / b * x;
}

 

posted @ 2020-05-17 22:09  Papayo  阅读(218)  评论(0编辑  收藏  举报