[自用]模板坑待填

Kruskal 最小生成树

重要程度:★★★★☆

熟练程度:★★★★☆

代码比较短,还是好理解,就是打的少了点

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
struct save
{
       int from;int to;int quan;

}cun[10000];
bool aaa(const save &s,const save &b)
{
        return s.quan<b.quan;
}
int fa[10000];
int find(int x)
{
    if(fa[x]!=x)
       fa[x]=find(fa[x]);
    return fa[x];
}
int ans=0;
int main()
{
    cin>>n>>m;//m条路径
    for(int i=1;i<=m;i++)
    {  int x,y,z;
       cin>>x>>y>>z;
       cun[i].from=x;cun[i].to=y;cun[i].quan=z;
    }
    for(int i=1;i<=10000;i++)
       fa[i]=i;
    sort(cun+1,cun+m+1,aaa);
    int sum=0;
    for(int i=1;i<=m;i++)
    {
            int x=cun[i].from;int y=cun[i].to;
            if(find(x)!=find(y))
            {
               fa[find(y)]=find(x);
               ans+=cun[i].quan;//cout<<ans<<"  "<<i<<endl;
               sum++;
            }
            if(sum==n-1)
              break;
    }

    cout<<ans;
    while(1);
    return 0;
}

Kruskal

Prim 最小生成树

重要程度:★★★☆☆

熟练程度:☆☆☆☆☆

好像只是听说过一样。几乎没怎么用过,但是有的题卡Kruskal

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,sum;
int a[2000][2000];
int dis[2000];
int pre[2000];
void prim(int x)
{
     sum=0;
     for(int i=1;i<=n;i++)
     {
        dis[i]=a[x][i];
        pre[i]=x;
     }
     dis[x]=0;
     for(int i=2;i<=n;i++)
     {
        int min=10000000;
        int k;
        for(int j=1;j<=n;j++)
        {
                if(dis[j]<min&&dis[j]!=0)
                {
                   min=dis[j];
                   k=j;
                }

        }
        sum+=dis[k];
        dis[k]=0;
        for(int j=1;j<=n;j++)
        {
                if(dis[j]>a[k][j])
                {   dis[j]=a[k][j];
                    pre[j]=k;
                }
        }
     }
}
int main()
{
    cin>>n>>m;
    memset(a,0x3f,sizeof(a));
    for(int i=1;i<=m;i++)
    {
       int x,y,z;
       cin>>x>>y>>z;
       a[x][y]=z;
       a[y][x]=z;
    }
    prim(1);int tot=0;
    cout<<sum;
    while(1);
    return 0;
}

Prim

线段树

重要程度:★★★★★

熟练程度:★★★★☆

很常用也很重要的数据结构,但是自己打一些灵活的线段树有一丝丝虚

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100010;
int a[N];
int t;
struct haha
{
       int left,right,sum;
}tree[N*4];
void buildtree(int left,int right,int i)
{
   int mid;
   tree[i].left=left;
   tree[i].right=right;
   if(left==right)
   {
     tree[i].sum=a[left];
     return;
   }
   mid=(left+right)>>1;
   buildtree(left,mid,i*2);
   buildtree(mid+1,right,i*2+1);
   tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}
void add(int haha,int num,int i)
{
    if(tree[i].left==tree[i].right)
    {
        tree[i].sum+=num;
        return;
    }
    else
    {
        tree[i].sum+=num;
        if(haha<=tree[i*2].right)
            add(haha,num,2*i);
        else
            add(haha,num,2*i+1);
    }
}

int query(int left,int right,int i)
{
    int mid;
    if(tree[i].left==left&&tree[i].right==right)
        return tree[i].sum;
    mid=(tree[i].left+tree[i].right)>>1;
    if(right<=mid)
        return query(left,right,2*i);
    else
       if(left>mid)
        return query(left,right,2*i+1);
       else
        return query(left,mid,2*i)+query(mid+1,right,2*i+1);
}
int n;
int k;
int main()
{
       //freopen("shulie.in","r",stdin);
       //freopen("shulie.out","w",stdout);
       char s[10];
       scanf("%d",&n);
       if(n==0)
        return 0;
       for(int i=1;i<=n;i++)
         scanf("%d",&a[i]);
       buildtree(1,n,1);
       int qq;
       scanf("%d",&qq);
       for(int i=1;i<=qq;i++)
       {
               scanf("%s",s);

               int haha,num;
               scanf("%d%d",&haha,&num);
               if(s[0]==‘S‘)
                 printf("%d\n",query(haha,num,1));
               if(s[0]==‘A‘)
                 add(haha,num,1);

       }
    //while(1);
    return 0;
}

普通线段树

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
using namespace std;
int n;
const int N=101000;
LL sum[N*4];
LL add[N*4];
void buildtree(int l,int r,int rt)
{
     add[rt]=0;
     if(l==r)
     {
        scanf("%lld",&sum[rt]);
        return;
     }
     int mid=(l+r)>>1;
     buildtree(l,mid,rt*2);
     buildtree(mid+1,r,rt*2+1);
     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int len)
{
     if(add[rt])
     {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(len-(len>>1));
        sum[rt<<1|1]+=add[rt]*(len>>1);
        add[rt]=0;
     }
}
void update(int xunl,int xunr,int c,int l,int r,int rt)
{
     if(xunl<=l&&r<=xunr)
     {
       add[rt]+=c;
       sum[rt]+=(LL)c*(r-l+1);
       return;
     }
     pushdown(rt,r-l+1);
     int mid=(l+r)>>1;
     if(xunl<=mid)
       update(xunl,xunr,c,l,mid,rt*2);
     if(mid<xunr)
       update(xunl,xunr,c,mid+1,r,rt*2+1);
     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
LL ques(int xunl,int xunr,int l,int r,int rt)
{
     if(xunl<=l&&r<=xunr)
       return sum[rt];
     pushdown(rt,r-l+1);
     int mid=(l+r)>>1;
     LL ans=0;
     if(xunl<=mid)
        ans+=ques(xunl,xunr,l,mid,rt*2);
     if(mid<xunr)
        ans+=ques(xunl,xunr,mid+1,r,rt*2+1);
     return ans;
}
int main()
{
    scanf("%d",&n);
    buildtree(1,n,1);
    int m;
    cin>>m;
    char s[20];
    for(int i=1;i<=m;i++)
    {
       scanf("%s",&s);
       int x,y,z;
       scanf("%d%d",&x,&y);
       if(s[0]==‘S‘)
       {
             printf("%lld\n",ques(x,y,1,n,1));
       }
       if(s[0]==‘A‘)
       {
             scanf("%d",&z);
             update(x,y,z,1,n,1);
       }
    }
    //while(1);
    return 0;
}

延迟标记线段树

扩展GCD

重要程度:★★★★★

熟练程度:★★★★☆

非常常用的数学知识,但是也有一些虚

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL x,y;
LL kuogcd(LL a,LL b,LL &x,LL &y)
{
   LL ret,tmp;
   if(b==0)
   {
           x=1;
           y=0;
           return a;
   }
   ret=kuogcd(b,a%b,x,y);
   tmp=x;
   x=y;
   y=tmp-a/b*y;
   return ret;
}
int main()
{
    LL m,n;
    cin>>m>>n;
    LL z;
    z=kuogcd(m,n,x,y);
    LL t=0;
    while(x<0)
    {
              x+=n*t;
              t++;
    }
    cout<<x;
    //while(1);
    return 0;
}

扩展GCD

匈牙利算法

重要程度:★★★☆☆

熟练程度:☆☆☆☆☆

最近做题很少有出现过,模板也几乎记住不了

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 2005;
bool vis[N];
int link[N],head[N];
int cnt,n;
struct Edge
{
    int to;
    int next;
};
Edge edge[N*N];
void Init()
{
    cnt = 0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
bool dfs(int u)
{
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v = edge[i].to;
        if(!vis[v])
        {
            vis[v] = 1;
            if(link[v] == -1 || dfs(link[v]))
            {
                link[v] = u;
                return true;
            }
        }
    }
    return false;
}
int match()
{
    int ans = 0;
    memset(link,-1,sizeof(link));
    for(int i=0;i<n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i)) ans++;
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&n))
    {
        Init();
        for(int i=0;i<n;i++)
        {
            int u,v,k;
            scanf("%d:(%d)",&u,&k);
            while(k--)
            {
                scanf("%d",&v);
                add(u,v);
                add(v,u);
            }
        }
        printf("%d\n",match()>>1);
    }
    return 0;
}

匈牙利算法

Tarjan缩点

重要程度:★★★★★

熟练程度:★☆☆☆☆

这么重要的知识我竟然脑子里留下的不多。看来得再多打两道题了

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 2000
int n,m;
int in[N];
struct haha
{
    int to,next,w;
};
haha edgechu[N],edge[N];
int headchu[N],cntchu=1,head[N],cnt=1,cntt;
int low[N],dfn[N],stack[N],hea,instack[N],belong[N],ji=1;
void addchu(int u,int v)
{
     edgechu[cntchu].to=v;
     edgechu[cntchu].next=headchu[u];
     headchu[u]=cntchu++;
}
void add(int u,int v)
{
     edge[cnt].to=v;
     edge[cnt].next=head[u];
     head[u]=cnt++;
}
void tarjan(int now)
{
     low[now]=dfn[now]=ji;
     ji++;
     stack[++hea]=now;
     instack[now]=1;
     for(int r=headchu[now];r;r=edgechu[r].next)
     {
        int i=edgechu[r].to;
        if(dfn[i]==-1)
        {
           tarjan(i);
           low[now]=min(low[now],low[i]);
        }
        else
           if(instack[i])
             low[now]=min(low[now],dfn[i]);
     }
     if(low[now]==dfn[now])
     {
        int temp;
        while(1)
        {
            temp=stack[hea--];
            belong[temp]=cntt;
            instack[temp]=0;
            if(temp==now)
               break;
        }
        cntt++;
     }
}
int main()
{
    memset(dfn,-1,sizeof(dfn));
    scanf("%d%d",&n,&m);
    pos(i,1,m)
    {
      int x,y;
      scanf("%d%d",&x,&y);
      addchu(x,y);
    }
    pos(i,1,n)
     if(dfn[i]==-1)
       tarjan(i);
    pos(i,1,n)
    {
      for(int v=headchu[i];v;v=edgechu[v].next)
      {
              int j=edgechu[v].to;
              if(belong[i]!=belong[j])
              {
                 add(belong[i],belong[j]);
                 in[belong[j]]++;
              }
      }
    }
    //while(1);
    return 0;
}

Tarjan缩点

Tarjan割点割边

重要程度:★★★★☆

熟练程度:★☆☆☆☆

这个也很重要了,最近做题做过一道,却发现自己还得再照着模板打

#include<iostream>
#include<cstdio>
#include<cstring>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 1000
using namespace std;
int a[N][N];
int n;
int gen,ji;
int dfn[N],low[N];
bool flag[N];
int gpoint[N];
void tarjan(int now)
{
     dfn[now]=low[now]=++ji;
     flag[now]=1;
     pos(i,1,n)
     {
        if(a[now][i]==1)
        {
          if(flag[i]==0)
          {
             tarjan(i);
             low[now]=min(low[now],low[i]);
             if(low[i]>=dfn[now]&&now!=1)
               gpoint[now]++;
             else
               if(now==1)
                 gen++;
          }
          else
            low[now]=min(low[now],dfn[i]);
        }
     }
}
int ans=0;
int main()
{
    cin>>n;int x,y;
    while(cin>>x)
    {
       cin>>y;
       a[x][y]=a[y][x]=1;
    }
    tarjan(1);
    if(gen>=2)
    {
      ans++;
      gpoint[1]=1;
    }
    pos(i,2,n)
      if(gpoint[i]!=0)
        ans++;
    if(ans!=0)
    {
      cout<<ans<<endl;
      pos(i,1,n)
      if(gpoint[i]!=0)
        cout<<i<<endl;
    }
    else
      cout<<0;
    //while(1);
    return 0;
}

Tarjan割点

/*tarjan算法--求无向图的割点和桥
一.基本概念
    1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。
    2.割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。
二:tarjan算法在求桥和割点中的应用
    1.割点:1)当前节点为树根的时候,条件是“要有多余一棵子树”(如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了。)
              2)当前节点U不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。
                  保证v向上最多翻到u才可以
    2.桥:若是一条无向边(u,v)是桥,
            1)当且仅当无向边(u,v)是树枝边的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u--v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥。
            如果v能上翻到u那么u--v就是一个环,删除其中一条路径后,能然是连通的。
    3.注意点:
 1)求桥的时候:因为边是无方向的,所以父亲孩子节点的关系需要自己规定一下,
 tarjan的过程中if(v不是u的父节点) low[u]=min(low[u],dfn[v]);
因为如果v是u的父亲,那么这条无向边就被误认为是环了。
  2)找桥的时候:注意看看有没有重边,有重边的边一定不是桥,也要避免误判。

    4.也可以先进行tarjan(),求出每一个点的dfn和low,并记录dfs过程中的每个点的父节点,遍历所有点的low,dfn来寻找桥和割点

三:求桥和割点的模板:
*/ 

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<vector>
#define N 201
vector<int>G[N];
int n,m,low[N],dfn[N];
bool is_cut[N];
int father[N];
int tim=0;
void input()
{
    scanf("%d%d",&n,&m);
    int a,b;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&a,&b);
        G[a].push_back(b);/*邻接表储存无向边*/
        G[b].push_back(a);
    }
}
void Tarjan(int i,int Father)
{
    father[i]=Father;/*记录每一个点的父亲*/
    dfn[i]=low[i]=tim++;
    for(int j=0;j<G[i].size();++j)
    {
        int k=G[i][j];
        if(dfn[k]==-1)
        {
            Tarjan(k,i);
            low[i]=min(low[i],low[k]);
        }
        else if(Father!=k)/*假如k是i的父亲的话,那么这就是无向边中的重边,有重边那么一定不是桥*/
            low[i]=min(low[i],dfn[k]);
            //dfn[k]可能!=low[k](搜索树中的树枝边,不是搜索树的根,因为i的儿子节点k有可能通过自己的一个反向边把自己的low更新了),
            //所以不能用low[k]代替dfn[k],否则会上翻过头了。
    }
}
void count()
{
    int rootson=0;
    Tarjan(1,0);
    for(int i=2;i<=n;++i)
    {
        int v=father[i];
        if(v==1)
           rootson++;/*统计根节点子树的个数,根节点的子树个数>=2,就是割点*/
        else{
            if(low[i]>=dfn[v])/*割点的条件*/
                is_cut[v]=true;
        }
    }
    if(rootson>1)
        is_cut[1]=true;
    for(int i=1;i<=n;++i)
      if(is_cut[i])
         printf("%d\n",i);
    for(int i=1;i<=n;++i)
    {
        int v=father[i];
        if(v>0&&low[i]>dfn[v])/*桥的条件*/
        printf("%d,%d\n",v,i);
    }

}
int main()
{
    input();
    memset(dfn,-1,sizeof(dfn));
    memset(father,0,sizeof(father));
    memset(low,-1,sizeof(low));
    memset(is_cut,false,sizeof(is_cut));
    count();
    return 0;
}

割点割边模板

A*

重要程度:★★★☆☆

熟练程度:★☆☆☆☆

很久没出过A*的题了,都忘了。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 200000
#define INF 0x7fffffff
struct haha
{
       int to,w,next;
};
haha edge1[N],edge2[N];
int head1[N],head2[N];
int cnt1=1,cnt2=1;
int dis[N];
void add2(int u,int v,int w)
{
     edge2[cnt2].w=w;
     edge2[cnt2].to=v;
     edge2[cnt2].next=head2[u];
     head2[u]=cnt2++;
}
void add1(int u,int v,int w)
{
     edge1[cnt1].w=w;
     edge1[cnt1].to=v;
     edge1[cnt1].next=head1[u];
     head1[u]=cnt1++;
}
int flag[N];
void spfa(int x)
{
     memset(dis,0x3f,sizeof(dis));
     queue<int> q;
     flag[x]=1;
     dis[x]=0;
     q.push(x);
     while(!q.empty())
     {
         int i=q.front();
         for(int v=head2[i];v;v=edge2[v].next)
         {
             int j=edge2[v].to;
             if(dis[j]>dis[i]+edge2[v].w)
             {
               dis[j]=dis[i]+edge2[v].w;
               if(!flag[j])
               {
                   flag[j]=1;
                   q.push(j);
               }
             }
         }
         flag[q.front()]=0;
         q.pop();
     }
}
struct node2
{
       int g,f,to;
       bool operator<(const node2 &r )const
       {
            if(r.f==f)
             return r.g<g;
            return r.f<f;
       }
};
int astar(int s,int t,int k)
{
    node2 e,ne;
    int cnt=0;
    priority_queue<node2> Q;
    if(s==t)
      k++;
    if(dis[s]>1000000)
      return -1;
    e.to=s;e.g=0;e.f=e.g+dis[e.to];
    Q.push(e);
    while(!Q.empty())
    {
       e=Q.top();
       Q.pop();
       if(e.to==t)
         cnt++;
       if(cnt==k)
         return e.g;
       for(int i=head1[e.to];i;i=edge1[i].next)
       {
         ne.to=edge1[i].to;
         ne.g=e.g+edge1[i].w;
         ne.f=ne.g+dis[ne.to];
         Q.push(ne);
       }
    }
    return -1;
}
int main()
{
    //freopen("dota.in","r",stdin);
    //freopen("dota.out","w",stdout);
    cin>>n>>m;
    pos(i,1,m)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add2(x,y,z);
        add2(y,x,z);
        add1(x,y,z);
        add1(y,x,z);
    }
    spfa(n);
    int p;
    cin>>p;
    if(p==0)
      printf("%d",dis[1]);
    else
        printf("%d",astar(1,n,2));
    //while(1);
    return 0;
}

A*

倍增LCA

重要程度:★★★★★

熟练程度:★★★☆☆

非常非常重要的,一定要记得熟熟的!其他LCA打法就先放一边吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define N 100000
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
int n,m;
struct haha
{
       int to,next,w;
}edge[N];
int head[N],cnt=1;
int f[N],p[N][20],deep[N],dis[N];
void add(int u,int v,int w)
{
     edge[cnt].w=w;
     //cout<<"w="<<w<<endl;
     edge[cnt].to=v;
     edge[cnt].next=head[u];
     head[u]=cnt++;
}
void dfs(int now,int fa,int de)
{
     f[now]=fa;
     deep[now]=de;
     for(int i=head[now];i;i=edge[i].next)
     {
        int v=edge[i].to;
        if(v!=fa)
        {
          dis[v]=dis[now]+edge[i].w;
          //cout<<dis[now]<<endl;
          dfs(v,now,de+1);
        }
     }
}
void init()
{
     int j;
     for(j=0;(1<<j)<=n;j++)
       pos(i,1,n)
         p[i][j]=-1;
     pos(i,1,n)
       p[i][0]=f[i];
     for(j=1;(1<<j)<=n;j++)
       pos(i,1,n)
         if(p[i][j-1]!=-1)
           p[i][j]=p[p[i][j-1]][j-1];
}
int lca(int a,int b)
{
    int i;
    if(deep[a]<deep[b])
      swap(a,b);
    for(i=0;(1<<i)<=deep[a];i++);
    i--;
    for(int j=i;j>=0;j--)
      if(deep[a]-(1<<j)>=deep[b])
        a=p[a][j];
    if(a==b) return a;
    for(int j=i;j>=0;j--)
      if(p[a][j]!=-1&&p[a][j]!=p[b][j])
      {
         a=p[a][j];
         b=p[b][j];
      }
    return f[a];
}
int main()
{
    scanf("%d%d",&n,&m);
    pos(i,1,m)
    {
       int x,y,w;
       char r;
       //scanf("%d%d%d",&x,&y,&w);
       scanf("%d%d%d",&x,&y,&w);
       cin>>r;
       //cout<<"wwww="<<w<<endl;
       add(x,y,w);
       add(y,x,w);
    }
    //dis[1]=0;
    dfs(1,-1,0);
    init();
    int k;
    scanf("%d",&k);
    while(k--)
    {
       int x,y;
       scanf("%d%d",&x,&y);
       //cout<<dis[y]<<endl;
       printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]);
    }
    //while(1);
    return 0;
}

倍增LCA

树链剖分

重要程度:★★★★★

熟练程度:★☆☆☆☆

想当初至少打了10遍的,无奈太长还是记不太清

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 50000
int n;
int read()
{
    int su=0;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)
       ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)
    {
                           su=su*10+ch-‘0‘;
                           ch=getchar();
    }

    return su;
}
struct haha
{
    int to,next,w,from;
}edge[N];
struct xixi
{
    int left,right,da;
}tree[N];
int head[N],cnt=1;
int size[N],son[N],dep[N],fa[N],v[N];
void add(int u,int v,int w)
{
     edge[cnt].w=w;
     edge[cnt].to=v;
     edge[cnt].from=u;
     edge[cnt].next=head[u];
     head[u]=cnt++;
}
void dfs(int x)
{
     size[x]=1;son[x]=0;
     for(int i=head[x];i;i=edge[i].next)
     {
        int to=edge[i].to;
        if(to!=fa[x])
        {
            fa[to]=x;
            v[to]=edge[i].w;
            dep[to]=dep[x]+1;
            dfs(to);
            size[x]+=size[to];
            if(size[to]>size[son[x]])
              son[x]=to;
        }
     }
}
int ji,pos[N],id[N],top[N];
void dfs2(int x,int tp)
{
     top[x]=tp;
     id[x]=++ji;
     pos[ji]=x;
     if(son[x])
        dfs2(son[x],tp);
     for(int i=head[x];i;i=edge[i].next)
     {
        int to=edge[i].to;
        if(to!=fa[x]&&to!=son[x])
          dfs2(to,to);
     }
}
void build(int left,int right,int root)
{
     tree[root].left=left;
     tree[root].right=right;
     if(left==right)
     {
         tree[root].da=v[pos[left]];
         return;
     }
     int mid=(right+left)>>1;
     build(left,mid,root*2);
     build(mid+1,right,root*2+1);
     tree[root].da=max(tree[root<<1].da,tree[root<<1|1].da);
}
int query(int left,int right,int root)
{
    int mid=(tree[root].right+tree[root].left)>>1;
    if(tree[root].left==left&&tree[root].right==right)
       return tree[root].da;
    if(right<=mid)
      return query(left,right,root*2);
    else
      if(left>mid)
        return query(left,right,root*2+1);
      else
        return max(query(left,mid,root*2),query(mid+1,right,root*2+1));
}
int Query(int x,int y)
{
    int fx=top[x],fy=top[y];
    int ans=1<<31;
    while(fx^fy)
    {
       if(dep[fx]<dep[fy])
       {
          swap(x,y);
          swap(fx,fy);
       }
       ans=max(ans,query(id[fx],id[x],1));
       x=fa[fx];fx=top[x];
    }
    if(dep[x]>dep[y])
      swap(x,y);
    if(id[x]<id[y])
      ans=max(ans,query(id[x]+1,id[y],1));
    return ans;
}
void change(int pos,int val,int root,int left,int right)
{
     if(left==right)
     {
         tree[root].da=val;
         return;
     }
     int mid=(left+right)>>1;
     if(pos<=mid)
       change(pos,val,root*2,left,mid);
     else
       change(pos,val,root*2+1,mid+1,right);
     tree[root].da=max(tree[root*2].da,tree[root*2+1].da);

}
char a[20];
int main()
{
    //freopen("qtree.in","r",stdin);
    //freopen("qtree.out","w",stdout);
    n=read();
    pos(i,1,n-1)
    {
       int x,y,z;
       x=read();y=read();z=read();
       add(x,y,z);add(y,x,z);
    }
    dfs(1);
    dfs2(1,1);
    build(1,n,1);
    while(1)
    {
        scanf("%s",&a);
        if(a[0]==‘D‘)
          break;
        int x,y;
        x=read();y=read();

        if(a[0]==‘Q‘)
            printf("%d\n",Query(x,y));
        else
        {
            int now=x*2-1;
            int fr=edge[now].from;
            int to=edge[now].to;
            if(fa[fr]==to)
              change(id[fr],y,1,1,n);
            else
              change(id[to],y,1,1,n);
        }
    }

    //while(1);
    return 0;
}

树链剖分

分块

重要程度:★★★★★

熟练程度:★★★★☆

关键时刻的救命暴力,一遍100%对还是有点虚

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 50100
int t;
int len,cun[N],match[N],a[N];
int n;
void del()
{
     memset(cun,0,sizeof(cun));
     memset(match,0,sizeof(match));
     memset(a,0,sizeof(a));
}
void pre(int x)
{
     pos(i,1,n)
       if(match[i]==x)
         cun[x]+=a[i];
}
void add(int x,int y)
{
     cun[match[x]]+=y;
     a[x]+=y;
}
int query(int x,int y)
{
    int ans=0;
    if(match[x]+1>=match[y])
      pos(i,x,y)
        ans+=a[i];
    else
    {
        for(int i=x;i;i++)
        {
           if(match[i]!=match[x])
             break;
           ans+=a[i];
        }
        for(int i=y;i;i--)
        {
           if(match[i]!=match[y])
             break;
           ans+=a[i];
        }
        pos(i,match[x]+1,match[y]-1)
          ans+=cun[i];
    }
    return ans;
}
int main()
{
    scanf("%d",&t);
    pos(u,1,t)
    {
       del();
       scanf("%d",&n);
       len=(int)sqrt(n+0.5);
       //while(1);
       pos(i,1,n)
         scanf("%d",&a[i]);
       pos(i,1,n)
          match[i]=(i-1)/len+1;
       pos(i,1,match[n])
         pre(i);
       printf("Case %d:\n",u);
       char s[20];
       while(1)
       {
          scanf("%s",&s);
          int x,y;
          if(s[0]==‘E‘)
            break;
          scanf("%d%d",&x,&y);
          if(s[0]==‘A‘)
            add(x,y);
          if(s[0]==‘S‘)
            add(x,-y);
          if(s[0]==‘Q‘)
            printf("%d\n",query(x,y));
       }
    }
   // while(1);
    return 0;
}

分块

字符串KMP

重要程度:★★★★★

熟练程度:★★★☆☆

字符串必备基础,但是变形还是虚

KMP

字符串Hash

重要程度:★★★★★

熟练程度:★★★☆☆

也是保命之作

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define N 1010000
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
unsigned long long haxi[N],haxi2[N];
int len2,len;
const int p=123;
char Q[N],P[N];
int t;
int aa;
unsigned long long xp[N];
void Hash(int n)
{
     memset(haxi,0,sizeof(haxi));
     pos2(i,n-1,0)
       haxi[i]=haxi[i+1]*p+P[i]-‘A‘;

}
void Hash2(int n)
{
     memset(haxi2,0,sizeof(haxi2));
     pos2(i,n-1,0)
       haxi2[i]=haxi2[i+1]*p+Q[i]-‘A‘;
     xp[0]=1;
     pos(i,1,n)
       xp[i]=xp[i-1]*p;
}
unsigned long long gethash(int i,int j)
{
     return haxi2[i]-haxi2[j]*xp[j-i];
}
void work()
{
     unsigned long long temp=haxi[0];
     pos(i,0,len2-len)
     {
         if(temp==gethash(i,i+len))
           aa++;
     }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
       aa=0;
       scanf("%s%s",P,Q);
       len=strlen(P);
       len2=strlen(Q);
       Hash(len);
       Hash2(len2);
       work();
       cout<<aa<<endl;
    }
    //while(1);
    return 0;
}

字符串Hash

Trie树

重要程度:★★★★☆

熟练程度:★☆☆☆☆

当初就打了两道题,印象很模糊了

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 500001
using namespace std;
struct Trie
{
       int dfn;
       Trie *ch[30];
};
Trie node[N],*root;
int f[N],n,t,sz;
Trie* newnode()
{
      sz++;
      return &node[sz];
}
void insert(char *s)
{
     int len=strlen(s);
     Trie *now=root;
     ++t;
     pos(i,0,len-1)
     {
        if(now->ch[s[i]-‘a‘]==NULL)
          now->ch[s[i]-‘a‘]=newnode();
        if(now->dfn)
          f[t]=max(f[now->dfn],f[t]);
        now=now->ch[s[i]-‘a‘];
     }
     now->dfn=t;
     f[t]++;
}
int main()
{
    scanf("%d",&n);
    root=newnode();
    pos(i,1,n)
    {
       char s[60];
       scanf("%s",s);
       insert(s);
    }
    int ans=0;
    pos(i,1,t)
      ans=max(ans,f[i]);
    printf("%d",ans);
    //while(1);
    return 0;
}

Trie

高斯消元

重要程度:★★★★☆

熟练程度:★☆☆☆☆

概率&期望必备!但是也是记忆不清楚了

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 600
using namespace std;
int n;
double a[N][N],b[N],x[N];
int flag;
void swap(double &xx,double &yy)
{
     double temp;
     temp=xx;
     xx=yy;
     yy=temp;
}
int gauss()
{
    double t;
    int im,num=1;
    for(int k=1;k<n;k++,num++)
    {
        im=k;
        pos(i,k+1,n)
           if(fabs(a[i][k])>fabs(a[im][k]))
             im=i;
        if(im!=k)
        {
           pos(i,k,n)
             swap(a[num][i],a[im][i]);
           swap(b[num],b[im]);
        }
        if(!a[num][k])
        {
           num--;
           continue;
        }
        pos(i,num+1,n)
        {
           if(!a[num][k])
             continue;
           t=a[i][k]/a[num][k];
           pos(j,k,n+1)
              a[i][j]-=t*a[k][j];
           b[i]-=t*b[k];
        }
    }
    pos(i,num,n)
      if(!a[i][n]&&b[i])
        return -1;
    pos2(i,n,1)
    {
       pos2(j,n,i+1)
         b[i]-=a[i][j]*x[j];
       if(!a[i][i]&&b[i]!=0)
         return -1;
       if(!a[i][i]&&!b[i])
         return 0;
       x[i]=b[i]/a[i][i];
    }
    return 1;
}
int haha()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d",&n);
    pos(i,1,n)
    {
       pos(j,1,n)
         scanf("%lf",&a[i][j]);
       scanf("%lf",&b[i]);
    }
    flag=gauss();
    if(flag!=1)
      printf("%d",flag);
    else
       pos(i,1,n)
       {
           if(!x[i])
             printf("x%d=0\n",i);
           else
             printf("x%d=%0.2lf\n",i,x[i]);
       }
    //while(1);
    return 0;
}
int sb=haha();
int main()
{;}

高斯消元

网络流

重要程度:★★★☆☆

熟练程度:★☆☆☆☆

对我来说就是一个大黑箱。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
#define LL long long
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 40000
const int inf=0x7fffffff;
struct haha{
    int next,to,w;
}edge[N];
int head[N],cnt;
int n;
void add(int u,int v,int w){
    edge[cnt].w=w;
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int dep[N],ans;
bool bfs(){
    memset(dep,0,sizeof(dep));
    queue<int> q;
    q.push(1);
    dep[1]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=head[now];i!=-1;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w;
            if(w&&(!dep[to])){
                dep[to]=dep[now]+1;
                q.push(to);
                if(to==n){
                    return 1;
                }
            }
        }
    }
    return 0;
}
int dfs(int now,int f){
    if(now==n){
        return f;
    }
    int tmp=f;
    for(int i=head[now];i!=-1;i=edge[i].next){
        int to=edge[i].to,w=edge[i].w;
        if(w&&tmp&&dep[to]==dep[now]+1){
            int k=dfs(to,min(w,tmp));
            if(!k){
                dep[to]=0;
                continue;
            }
            edge[i].w-=k;
            edge[i^1].w+=k;
            tmp-=k;
        }
    }
    return f-tmp;
}
int main(){
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    pos(i,1,n){
        pos(j,1,n){
            int x;
            scanf("%d",&x);
            if(x){
                add(i,j,x);
                add(j,i,0);
            }
        }
    }
    while(bfs()){
        ans+=dfs(1,inf);
    }
    cout<<ans;
    return 0;
}

网络流最大流

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
#define LL long long
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 10000
#define inf 0x7fffffff
struct haha{
    int next,to,w,cost,from;
}edge[N];
int cnt=2,head[N];
int t,g,p,m,f,n,s;
void add(int u,int v,int w,int c){
    edge[cnt].w=w;
    edge[cnt].to=v;
    edge[cnt].cost=c;
    edge[cnt].from=u;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int S,T;
queue<int> q;
int dis[N],cun[N],flag[N],from[N],ans;
int spfa(int st,int ed)
{
      pos(i,st+1,ed){
          dis[i]=inf;
      }
      flag[st]=1;
      q.push(st);
      while(!q.empty())
      {
        int k=q.front();
        q.pop();
        flag[k]=0;
        for(int i=head[k];i;i=edge[i].next)
        {
          if(edge[i].w&&dis[edge[i].to]>dis[k]+edge[i].cost)
          {
            dis[edge[i].to]=dis[k]+edge[i].cost;
            if(!flag[edge[i].to])
              q.push(edge[i].to);
            flag[edge[i].to]=1;
            from[edge[i].to]=i;
          }
        }
      }
      if(dis[ed]==inf)
        return 0;
      return dis[ed];
}
int work(int st,int ed)
{
      int pp=ed,ff=inf;
      while(pp!=st)
      {
        ff=min(ff,edge[from[pp]].w);
        pp=edge[from[pp]^1].to;
      }
      pp=ed;
      while(pp!=st)
      {
        edge[from[pp]].w-=ff;
        edge[from[pp]^1].w+=ff;
        pp=edge[from[pp]^1].to;
      }
      return ff;
}
int MCMF(int st,int ed)
{
      int ret=0,l;
      while(l=spfa(st,ed))
        ret+=work(st,ed)*l;
      return ret;
}
void work(){
    pos(i,1,t){
        add(S,i,cun[i],0);
        add(i,S,0,0);

        add(S,i+t,inf,p);
        add(i+t,S,0,-p);

        add(i+t,T,cun[i],0);
        add(T,i+t,0,0);

        if(i+m<=t){
            add(i,i+m+t,inf,f);
            add(i+m+t,i,0,-f);
        }
        if(i+n<=t){
            add(i,i+n+t,inf,s);
            add(i+n+t,i,0,-s);
        }
        if(i!=t){
            add(i,i+1,inf,0);
            add(i+1,i,0,0);
        }
    }
}
int main(){
    freopen("napkin.in","r",stdin);
    freopen("napkin.out","w",stdout);
    scanf("%d",&t);
    T=t*2+1;
    pos(i,1,t){
        scanf("%d",&cun[i]);
    }
    scanf("%d%d%d%d%d",&p,&m,&f,&n,&s);
    work();
    ans=MCMF(S,T);
    cout<<ans;
    return 0;
}

最小费用最大流

欧拉函数线性筛

重要程度:★★★☆☆

熟练程度:★☆☆☆☆

貌似只会最暴力的求法

#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 1000500;
bool flag[MAXN];///标记数组
int phi[MAXN];///欧拉函数值,i的欧拉函数值=phi[i]
int p[MAXN];///素因子的值
int cnt = 0;
void Get_phi()///筛法求欧拉函数
{
    cnt = 0;
    memset(flag, true, sizeof(flag));
    phi[1] = 1;
    for(int i=2; i<MAXN; i++)///线性筛法
    {
        if(flag[i])///素数
        {
            p[cnt++] = i;
            phi[i] = i-1;///素数的欧拉函数值是素数 - 1
        }
        for(int j=0; j<cnt; j++)
        {
            if(i*p[j] > MAXN)
                break;
            flag[i*p[j]] = false;///素数的倍数,所以i*p[j]不是素数
            if(i%p[j] == 0)///性质:i mod p == 0, 那么 phi(i * p) == p * phi(i)
            {
                phi[i*p[j]] = p[j] * phi[i];
                break;
            }
            else
                phi[i*p[j]] = (p[j]-1) * phi[i];///i mod p != 0, 那么 phi(i * p) == phi(i) * (p-1)
        }
    }
}
int main()
{
    Get_phi();
    int m;
    while(cin>>m)///测试
    {
        cout<<phi[m]<<endl;
    }
    return 0;
}

欧拉函数线性筛

平衡树

重要程度:★★★★★

熟练程度:★★★☆☆

其重要性不言而喻,无奈码量太大

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 100000
int ch[N][3],size[N],w[N],v[N],fa[N];
int root,sz;
void clear(int x){
    ch[x][0]=ch[x][1]=fa[x]=w[x]=v[x]=size[x]=0;
}
int get(int x){
    return ch[fa[x]][1]==x;
}
void update(int x){
    if (x){
        size[x]=w[x];
        if (ch[x][0])
            size[x]+=size[ch[x][0]];
        if (ch[x][1])
            size[x]+=size[ch[x][1]];
    }
}
void rotate(int x){
    int old=fa[x],oldf=fa[old],which=get(x);
    ch[old][which]=ch[x][which^1];
    fa[ch[old][which]]=old;
    fa[old]=x;ch[x][which^1]=old;
    fa[x]=oldf;
    if (oldf)
        ch[oldf][ch[oldf][1]==old]=x;
    update(old);update(x);
}
void splay(int x){
    for (int f;(f=fa[x]);rotate(x))
        if (fa[f])
            rotate((get(x)==get(f)?f:x));
    root=x;
}
void insert(int x){
    if(!root){
        sz++;ch[sz][0]=ch[sz][1]=fa[sz]=0;
        size[sz]=w[sz]=1;
        v[sz]=x;
        root=sz;
        return;
    }
    int now=root,f=0;
    while(1){
        if(v[now]==x){
            w[now]++;
            update(now);update(f);
            splay(now);
            break;
        }
        f=now;now=ch[now][v[now]<x];
        if(!now){
            sz++;
            ch[sz][0]=ch[sz][1]=0;
            v[sz]=x;w[sz]=1;fa[sz]=f;
            ch[f][v[f]<x]=sz;
            update(f);
            splay(sz);
            break;
        }
    }
}
int find(int x){
    int ans=0,now=root;
    while(1){
        if(x<v[now]){
            now=ch[now][0];
        }
        else{
            ans+=(ch[now][0]?size[ch[now][0]]:0);
            if(x==v[now]){
                splay(now);
                return ans+1;
            }
            ans+=w[now];
            now=ch[now][1];
        }
    }
}
int findx(int x){
    int now=root;
    while(1){
        if(ch[now][0]&&x<=size[ch[now][0]]){
            now=ch[now][0];
        }
        else{
            int temp=(ch[now][0]?size[ch[now][0]]:0)+w[now];
            if(x<=temp)
                return v[now];
            x-=temp;
            now=ch[now][1];
        }
    }
}
int pre(){
    int now=ch[root][0];
    while(ch[now][1])
      now=ch[now][1];
    return now;
}
void del(int x){
    int whatever=find(x);
    if(w[root]>1){
        w[root]--;
        return;
    }
    if(!ch[root][0]&&!ch[root][1]){
        clear(root);
        root=0;
        return;
    }
    if(!ch[root][0]){
        int oldroot=root;
        root=ch[root][1];
        fa[root]=0;
        clear(oldroot);
        return;
    }
    else{
        if(!ch[root][1]){
            int oldroot=root;
            root=ch[root][0];
            fa[root]=0;
            clear(oldroot);
            return;
        }
    }
    int leftbig=pre(),oldroot=root;
    splay(leftbig);
    fa[ch[oldroot][1]]=root;
    ch[root][1]=ch[oldroot][1];
    clear(oldroot);
    update(root);
    return;
}
int next(){
    int now=ch[root][1];
    while(ch[now][0])
      now=ch[now][0];
    return now;
}

int main(){
    freopen("phs.in","r",stdin);
    freopen("phs.out","w",stdout);
    int n,opt,x;
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d%d",&opt,&x);
        switch(opt){
            case 1: insert(x); break;
            case 2: del(x); break;
            case 3: printf("%d\n",find(x)); break;
            case 4: printf("%d\n",findx(x)); break;
            case 5: insert(x); printf("%d\n",v[pre()]); del(x); break;
            case 6: insert(x); printf("%d\n",v[next()]); del(x); break;
        }
    }
    return 0;
}

Splay伸展树

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 501000
struct Treep{
    int l,r,w,v,size,rnd;
}tree[N];
int n;
int root,size;
void update(int k){
    tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+tree[k].w;
}
void lturn(int &k){
    int t=tree[k].r;
    tree[k].r=tree[t].l;
    tree[t].l=k;
    tree[t].size=tree[k].size;
    update(k);
    k=t;
}
void rturn(int &k){
    int t=tree[k].l;
    tree[k].l=tree[t].r;
    tree[t].r=k;
    tree[t].size=tree[k].size;
    update(k);
    k=t;
}
void insert(int &k,int x){
    if(k==0){
        size++;
        k=size;
        tree[k].w=tree[k].size=1;
        tree[k].v=x;
        tree[k].rnd=rand();
        return;
    }
    tree[k].size++;
    if(tree[k].v==x)
      tree[k].w++;
    else{
        if(tree[k].v<x){
            insert(tree[k].r,x);
            if(tree[tree[k].r].rnd<tree[k].rnd)
              lturn(k);
        }
        else{
            insert(tree[k].l,x);
            if(tree[tree[k].l].rnd<tree[k].rnd)
              rturn(k);
        }
    }
}
int tmp;
void query_pro(int k,int x){
    if(k==0)
      return;
    if(tree[k].v<x){
        tmp=k;
        query_pro(tree[k].r,x);
    }
    else
     query_pro(tree[k].l,x);
}
void query_sub(int k,int x){
    if(k==0)
      return;
    if(tree[k].v>x){
        tmp=k;
        query_sub(tree[k].l,x);
    }
    else
      query_sub(tree[k].r,x);
}
void del(int &k,int x){
    if(k==0)
      return;
    if(tree[k].v==x){
        if(tree[k].w>1){
            tree[k].w--;
            tree[k].size--;
            return;
        }
        if(tree[k].l*tree[k].r==0)
          k=tree[k].l+tree[k].r;
        else{
            if(tree[tree[k].l].rnd<tree[k].rnd){
                rturn(k);
                del(k,x);
            }
            else{
                lturn(k);
                del(k,x);
            }
        }
    }
    else{
        if(tree[k].v<x){
            tree[k].size--;
            del(tree[k].r,x);
        }
        else{
            tree[k].size--;
            del(tree[k].l,x);
        }
    }
}
int query_rank(int k,int x){
    if(k==0)
      return 0;
    if(tree[k].v==x)
       return tree[tree[k].l].size+1;
    else{
        if(tree[k].v<x)
            return tree[tree[k].l].size+tree[k].w+query_rank(tree[k].r,x);
        else
            return query_rank(tree[k].l,x);
    }
}
int query_num(int k,int x){
    if(k==0)
      return 0;
    if(tree[tree[k].l].size>=x)
      return query_num(tree[k].l,x);
    else{
        if(tree[tree[k].l].size+tree[k].w<x)
          return query_num(tree[k].r,x-tree[tree[k].l].size-tree[k].w);
        else
          return tree[k].v;
    }
}
int main()
{
    freopen("phs.in","r",stdin);
    freopen("phs.out","w",stdout);
    scanf("%d",&n);
    int opt,x;
    pos(i,1,n){
        scanf("%d%d",&opt,&x);
        switch(opt){
        case 1:insert(root,x);break;
        case 2:del(root,x);break;
        case 3:printf("%d\n",query_rank(root,x));break;
        case 4:printf("%d\n",query_num(root,x));break;
        case 5:tmp=0;query_pro(root,x);printf("%d\n",tree[tmp].v);break;
        case 6:tmp=0;query_sub(root,x);printf("%d\n",tree[tmp].v);break;
        }
    }
    //while(1);
    return 0;
}

Treap

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define inf 0x7fffffff
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
struct Treap{
    Treap *ch[2];
    int key,val,size;
    Treap(int v){
        size=1;val=v;key=rand();ch[0]=ch[1]=NULL;
    }
    void tain(){
        size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0);
    }
}*root;
typedef pair<Treap*,Treap*> D;
int size(Treap *o){
    return o?o->size:0;
}
Treap *merge(Treap *a,Treap *b){
    if(!a)  return b;
    if(!b)  return a;
    if(a->key < b->key){
        a->ch[1]=merge(a->ch[1],b);a->tain();return a;
    }
    else{
        b->ch[0]=merge(a,b->ch[0]);b->tain();return b;
    }
}
D split(Treap *o,int k){
    if(!o)  return D(NULL,NULL);
    D y;
    if(size(o->ch[0])>=k){
        y=split(o->ch[0],k);o->ch[0]=y.second;o->tain();y.second=o;
    }
    else{
        y=split(o->ch[1],k-size(o->ch[0])-1);
        o->ch[1]=y.first;
        o->tain();
        y.first=o;
    }
    return y;
}
int getkth(Treap *o,int v){
    if(o==NULL)  return 0;
    return (o->val >= v)?getkth(o->ch[0],v):getkth(o->ch[1],v)+size(o->ch[0])+1;
}
int findkth(int k){
    D x=split(root,k-1);
    D y=split(x.second,1);
    Treap *ans=y.first;
    root=merge(merge(x.first,ans),y.second);
    return ans!=NULL?ans->val:0;
}
void insert(int v){
    int k=getkth(root,v);
    D x=split(root,k);
    Treap *o=new Treap(v);
    root=merge(merge(x.first,o),x.second);
}
void del(int v){
    int k=getkth(root,v);
    D x=split(root,k);
    D y=split(x.second,1);
    root=merge(x.first,y.second);
}
int main(){
    freopen("phs.in","r",stdin);
    freopen("phs.out","w",stdout);
    int m,opt,x;scanf("%d",&m);
    while(m--)
    {
        scanf("%d%d",&opt,&x);
        switch(opt)
        {
            case 1:insert(x);break;
            case 2:del(x);break;
            case 3:printf("%d\n",getkth(root,x)+1);break;
            case 4:printf("%d\n",findkth(x));break;
            case 5:printf("%d\n",findkth(getkth(root,x)));break;
            case 6:printf("%d\n",findkth(getkth(root,x+1)+1));break;
        }
    }
    return 0;
}

无旋Treap

Graham扫描

重要程度:★☆☆☆☆

熟练程度:☆☆☆☆☆

这什么玩意。。好像联赛也不考

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
#define pos(i,a,b) for(long long i=(a);i<=(b);i++)
#define LL long long
#define eps 1e-8;
struct haha{
    double x,y;
    friend bool operator < (haha a,haha b){
        return (a.x==b.x)?a.y<b.y:a.x<b.x;
    }
    friend haha operator - (haha a,haha b){
        haha c;
        c.x=a.x-b.x;c.y=a.y-b.y;
        return c;
    }
}cun[10010];
vector<haha> v;
int s[10010],top;
double pow2(double x){
    return x*x;
}
double cross(haha a,haha b){
    return a.x*b.y-b.x*a.y;
}
double dis(haha &a,haha &b){
    return sqrt(pow2(a.x-b.x)+pow2(a.y-b.y));
}
bool check(haha a,haha b,haha c){
    return cross(b-a,c-a)>eps;
}
int n,flag[10010];
double ans;
int main(){
    freopen("fc.in","r",stdin);
    freopen("fc.out","w",stdout);
    scanf("%d",&n);
    pos(i,1,n){
        scanf("%lf%lf",&cun[i].x,&cun[i].y);
    }
    sort(cun+1,cun+n+1);
    s[++top]=1;s[++top]=2;
    pos(i,3,n){
        while(top>1&&!check(cun[s[top]],cun[i],cun[s[top-1]]))
            top--;
        s[++top]=i;
    }
    pos(i,1,top){
        flag[s[i]]=1;v.push_back(cun[s[i]]);
    }
    top=0;
    s[++top]=n;s[++top]=n-1;
    for(int i=n-2;i>=1;i--){
        while(top>1&&check(cun[s[top]],cun[s[top-1]],cun[i])){
            top--;
        }
        s[++top]=i;
    }
    pos(i,1,top){
        if(!flag[s[i]])
            v.push_back(cun[s[i]]);
    }
    for(int i=0,s=v.size();i<s;i++)
        ans+=dis(v[i],v[(i+1)%s]);
    printf("%0.2lf",ans);
    return 0;
}

Graham扫描

RMQ

重要程度:★☆☆☆☆

熟练程度:☆☆☆☆☆

我就没打过,全用的线段树

/*
    RMQ算法:用DP预处理  O(nlog(n))的复杂度,查询每次是O(1)的。

那么查询的时候对于任意一个区间 l -- r ,我们同样可以得到区间差值 len = (r - l + 1)。 

那么我们这一用小于2^k<=len,的 k 把区间分成可以交叉的两部分l 到 l+2^(k)- 1, 到 r -(1<<k)+1 到 r 的两部分,
很easy的求解了。

01.int rmq(int l,int r)
02.{
03.    int k=0;
04.    while((1<<(k+1))<=r-l+1)
05.        k++;
06.    //printf("%d %d %d %d\n",l,l+(1<<k),r-(1<<k)+1,r-(1<<k)+1+(1<<k));
07.    int ans1=max(mm[l][k],mm[r-(1<<k)+1][k]);
08.    int ans2=min(mi[l][k],mi[r-(1<<k)+1][k]);
09.    return ans1-ans2;
10.}  

*/

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>

using namespace std;

int a[100001];
int n,m;
int d[100001][110];

void RMQ_init()
{
    for (int i=1;i<=n;++i) d[i][0]=a[i];//以第i个数字为起点长度为2^0的序列的最小值,肯定先是自己。。
        for (int j=1;(1<<j)<=n;++j)//1<<J的意思是j*2;
             for (int i=1;i+(1<<j)-1<=n;++i)//i从1到i+2*j-1这个长度范围内,即分别求出每个ij的最小值。。
                  d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int RMQ(int l,int r)
{
      int k=0;

      while ((1<<(k+1))<=r-l+1) k++;//只要K+1小于这个查询序列的一半,就一直更新,因为要把序列从中间分开, 

      return min(d[l][k],d[r-(1<<k)+1][k]);
}
int main(){
    ios::sync_with_stdio(false);

    freopen("faithful.in","r",stdin);
    freopen("faithful.out","w",stdout);
    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }
    RMQ_init();
    for(int i=1;i<=m;++i){
        int x,y;

        scanf("%d%d",&x,&y);

        printf("%d",RMQ(x,y));
    }

    return 0;
}

RMQ

Dijkstra最短路

重要程度:★★☆☆☆

熟练程度:★☆☆☆☆

全用的SPFA

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
int a[5000],dis[5000],r[5000];
bool v[5000];
int n,tot = 0,m,aa,bb;
int xiao(int x,int y)
{
     if(x>y)
      return y;
     else return x;
}

int read()
{
    int su=0;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)
       ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)
    {
                           su=su*10+ch-‘0‘;
                           ch=getchar();
    }

    return su;
}
struct ddd
{
    int q,dat;
    friend bool operator < (ddd a, ddd b)
    {
        return a.dat > b.dat;
    }
};
priority_queue<ddd> que;
struct jie
{
    int in;
    int out;
    int quan,next;
}c[5000];
ddd cc;
void add(int x,int y, int z)
{
    c[++tot].in = x;
    c[tot].out = y;
    c[tot].quan = z;
    c[tot].next = r[x];
    r[x] = tot;
}
int dj(int u)
{
    int x,y;
    cc.q = u;
    cc.dat = 0;
    que.push(cc);
    memset(dis,0x7f,sizeof(dis));
    memset(v,0,sizeof(v));
    dis[u] = 0;
    while (!que.empty())
    {
        x=que.top().q;
        y=que.top().dat;
        que.pop();
        if(!v[x])
        {
            v[x] = true;
            for(int i=r[x];i;i=c[i].next)
            {
                cc.q = c[i].out;
                if(dis[cc.q]> y+c[i].quan)
                {
                   dis[cc.q]=y+c[i].quan;
                   cc.dat=dis[cc.q];
                   que.push(cc);
                }
            }
        }
    }
} 

int main()
{
    n=read();//个数
    m=read();//线路
    aa=read();//出发点
    bb=read();//目标点
    for(int i=1; i<=m; i++)
    {
        int x,y,z;
        x=read();
        y=read();
        z=read();
        add(x,y,z);
        add(y,x,z);
    }
    dj(aa);
    cout<<dis[bb];
    while(1);
    return 0;
}

Dijkstra堆优化

SPFA

重要程度:★★★★★

熟练程度:★★★★★

非常之熟悉,保命的

void spfa(int x){
    memset(dis,0x7f,sizeof(dis));
    memset(flag,0,sizeof(flag));
    queue<int> q;
    flag[x]=1;dis[x]=0;q.push(x);
    while(!q.empty()){
        int k=q.front();
        for(int i=head[k];i;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w;
            if(dis[to]>dis[k]+w){
                dis[to]=dis[k]+w;
                if(!flag[to]){
                    flag[to]=1;
                    q.push(to);
                }
            }
        }
        flag[q.front()]=0;
        q.pop();
    }
}

SPFA

并查集

重要程度:★★★★★

熟练程度:★★★★★

码量小,好理解,很熟悉

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,q;
int father[20050];
int read()
{
    int su=0;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)
       ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)
    {
                           su=su*10+ch-‘0‘;
                           ch=getchar();
    }

    return su;
}
int find(int x)//查找x的祖先
{
    if(father[x]!=x)
       father[x]=find(father[x]);
    return father[x];
}
void hebing(int x,int y)
{
     x=find(x);
     y=find(y);
     father[y]=x;
}
int main()
{
    cin>>n>>m; //n个人,m种关系
    for(int i=1;i<=n;i++)
      father[i]=i;
    for(int i=1;i<=m;i++)
    {
       int x,y;
       x=read();y=read();
       hebing(x,y);
    }
    int p[n+10];
    for(int i=1;i<=n;i++)
    {
            p[i]=find(i);
    }
    cin>>q;  //q种询问
    for(int i=1;i<=q;i++)
    {
       int x,y;
       x=read();y=read();
       if(p[x]==p[y])
         printf("Yes\n");
       else
         printf("No\n");
    }
    while(1);
    return 0;
}

并查集

树状数组

重要程度:★★★★★

熟练程度:★★★★★

码量小,好理解,很熟悉

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int t;
int ji=0;
int a[50010];
int c[50010];
int n;
int read()
{
    int su=0;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)
       ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)
    {
       su=su*10+ch-‘0‘;
       ch=getchar();
    }

    return su;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int x)
{
     while(i<=n)
     {
       c[i]+=x;
       i+=lowbit(i);
     }
}
int tot(int x)
{
    int sum=0;
    while(x>0)
    {
       sum+=c[x];
       x-=lowbit(x);
    }
    return sum;
}
int Sum(int i,int j)
{
    return tot(j)-tot(i-1);
}
int main()
{
    cin>>t;
    for(int i=1;i<=t;i++)
    {
       memset(a,0,sizeof(a));
       memset(c,0,sizeof(c));
       ji++;
       n=read();
       for(int i=1;i<=n;i++)
       {
          a[i]=read();
          add(i,a[i]);
       }
       printf("Case %d:\n",ji);
       //cout<<"Case "<<ji<<":"<<endl;
       char in[20];
       while(1)
       {
              scanf("%s",in);
              if(in[0]==‘E‘)
                break;
              int x,y;
              x=read();y=read();
              if(in[0]==‘Q‘)
              {
                 printf("%d\n",Sum(x,y));
              }
              if(in[0]==‘A‘)
              {
                 a[x]+=y;
                 add(x,y);
              }
              if(in[0]==‘S‘)
              {
                 a[x]-=y;
                 add(x,-y);
              }
       }

    }
    //while(1);
    return 0;
}

树状数组

单调队列

重要程度:★★★★★

熟练程度:★★★★★

码量小,好理解,很熟悉,优化DP必备

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 2500
int t,maxp,w;
int in[N],out[N],inmoney[N],outmoney[N];
int f[N][N];
int q[N],mp[N];
int head,tail;
int main()
{
    memset(f,-50,sizeof(f));
    scanf("%d%d%d",&t,&maxp,&w);
    pos(i,1,t)
         scanf("%d%d%d%d",&inmoney[i],&outmoney[i],&in[i],&out[i]);
    pos(i,1,w+1)
      f[i][0]=0;
    pos(i,1,w+1)
      pos(j,1,min(in[i],maxp))
        f[i][j]=-inmoney[i]*j;
    pos(i,1,t)
    {
          pos(j,0,maxp)
            f[i][j]=max(f[i][j],f[i-1][j]);
          if(i>w+1)
          {
               int tian=i-w-1;
               head=tail=0;int temp;
               pos(j,0,maxp)
               {
                    temp=f[tian][j]+j*inmoney[i];
                    while(head<tail&&q[tail-1]<temp)
                      tail--;
                    q[tail]=temp;mp[tail]=j;
                    tail++;
                    while(head<tail&&mp[head]+in[i]<j)
                      head++;
                    f[i][j]=max(f[i][j],q[head]-j*inmoney[i]);
               }
               head=tail=0;
               pos2(j,maxp,0)
               {
                    temp=f[tian][j]+j*outmoney[i];
                    while(head<tail&&q[tail-1]<temp)
                      tail--;
                    q[tail]=temp;mp[tail]=j;
                    tail++;
                    while(head<tail&&mp[head]-out[i]>j)
                      head++;
                    f[i][j]=max(f[i][j],q[head]-j*outmoney[i]);
               }

      }
    }
    int ans=0;
    pos(i,1,t)
      pos(j,0,maxp)
        ans=max(ans,f[i][j]);
    cout<<ans;
    //while(1);
    return 0;
}

单调队列优化DP

未完待续……

随着知识的学习还会有很多的模板要背,还会有很多的坑要填hhh

时间: 2024-10-12 15:27:44

[自用]模板坑待填的相关文章

挨踢部落故事汇(32): Java深坑如何填?

世上本没有坑,踩的人多了也便成了坑.每遇到一次困难,每踩一个坑,对程序员来说都是一笔财富.持续学习是程序员保持竞争力的源泉.本期将分享一个踩坑无数的Java程序猿填坑秘籍. 榆木,一个阅历无数(踩坑)的技术宅男,喜欢了解新技术却不爱太钻研新技术(因为懒,猿届反面角色一枚).14年毕业至今,在Java开发这条道路上可谓是坑过好些人.也埋过好些坑.也被坑过好些次.因为懒,没有针对他遇到过的问题做过太多的笔记(记录一些棘手问题的解决方法还是个不错的习惯),只是习惯性的去分析为什么出现这样的问题,我们该

svn的坑 想填的可以自己参考下

已经搭建好了svn 由于没有权限控制 被误删 结果又重新来一次 今天已经踩了无数的坑 无论是lanmp lnmp lamp的一键安装包,的确不推荐线上用,由于项目紧,就偷懒了,结果无数的坑 无数的添,不论是ssl认证还是 页面加载gzip压缩级别,疑惑是虚拟主机,跟开发代码的融合总是出现很大的问题,还好对于apache结构较熟悉. 不说了,最后一个坑就是svn 更新通过脚本提交后 直接在svn更新到线上,最后吐槽一下,谷歌,苹果校验,尤其是ipad appstore真心尼玛操蛋,还有某些领导,创

&lt;微影看&gt;巨坑开填一

前言:原本我想 哈哈,几分钟把微信公众号全部搞掂,然后去浪...才发现 我想多了.. 下面介绍如何填巨坑一!!! 这次目标:把微信公众号配置好,配置上URL Token,以便以后数据的连接. 首先要说一下,为什么说这次是巨坑,搭建个微信公众号那么简单也叫巨坑??? 这要从微信公众号的分类说起,微信公众号有三种:个人订阅号,服务号,企业号.每一种都各自特点,详情自己百度啊 哈哈哈. 我们 微影看 要有后台数据库网站语音搜索网页链接等功能接入,就必须要服务号或者企业号,这对于我们这些学生党是根本不可

CPython对象模型:string(留坑待填)

在python3中,移除了2中的byte string,string变的和2中的unicode类似.所以在python3中烦人的编码问题会少不少. 在准备动手写这一篇的时候,查了不少资料,结果不小心发现了PEP-393 这个是unicode部分的原作者亲自写的,内容详细解释的很清楚,只要对python对象有个基础的认识绝对看得懂啊! 于是为了先赶赶进度,我决定先给string留个坑,等以后再填……

由return所联想到的(挖个坑待填)

前几天写了个表单提交,由于还不会本地写个数据测试,于是就直接空着URL交给后台同学了.结果今天反馈回一个bug,说是button点击事件并没有用,还没点击就发生了. 举个简单的栗子. 1 <button id="bt">提交</button> //在外部的js文件中window.onload=function(){ var bt = document.getElementById("bt"); bt.onclick = alert("

移动前端:坑与填坑

1.页面高度渲染错误 坑:页面底部部分与浏览器导航条重合了 填坑:重置高度 document.documentElement.style.height = window.innerHeight + 'px'; 2.transform碰上模糊 坑:在android中,如果元素或其父元素应用transform后,元素设置border-radius会变模糊 填坑:先放大再缩小 body{padding: 20px;background:purple;-webkit-transform: transla

纯Socket(BIO)长链接编程的常见的坑和填坑套路

本文章纯属个人经验总结,伪代码也是写文章的时候顺便白板编码的,可能有逻辑问题,请帮忙指正,谢谢. Internet(全球互联网)是无数台机器基于TCP/IP协议族相互通信产生的.TCP/IP协议族分了四层实现,链路层.网络层.传输层.应用层. 与我们应用开发者接触最多的应该是应用层了,例如web应用普遍使用HTTP协议,HTTP协议帮助我们开发者做了非常多的事情,通过HTTP足以完成大部分的通信工作了,但是有时候会有一些特殊的场景出现,使得HTTP协议并不能得心应手的完成工作,这个时候就需要我们

入坑慢慢填

刚入大学,大一的大学的生活似乎比较的轻松,那时候就想着多学一些东西,也对未来就业有帮助,而且感觉软件这方面的东西很有兴趣,觉得发挥可以发挥自己的创造性,做属于自己的的东西,完成出很酷的东西.然后就进入了二专的软件.在过去的一年里,讲真很累,累的我常常想放弃.但咬牙过来以后,又觉得有一些小小的成就感,确切的说来应该是入坑无悔吧. 软件工程这个专业应该来说和我的专业的相关性应该是挺高的吧,二者应该可以很好地互补,我自己的本专业是机械电子工程,也会学习到或多或少的编程知识,虽然没有那么专业就是啦.开始

bzoj4025: 二分图(留坑后填)

这题想不出来. 不浪费时间了. 以后找时间填. 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8516221.html