模板

最短路

【1】dijkstra

priority_queue<pair<int,int> >q;
int d[maxn],vis[maxn];
void dijkstra()
{
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[0]=0;
    q.push(make_pair(0,0));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].to,v=edge[i].val;
            if(d[y]>d[x]+v){
                d[y]=d[x]+v;
                q.push(make_pair(-d[y],y));
            }
        }
    }
}

【2】spfa

最小生成树

【1】prim

int prim(int x)
{
    memset(vis,0,sizeof(vis));
    memset(d,0x3f,sizeof(d));
    int ans=0;
    d[1]=0;
    for(int i=1;i<=x;i++)
    {
        int t,m=1<<30;
        for(int j=1;j<=x;j++)
            if(!vis[j] && d[j]<m)
            {
                m=d[j];
                t=j;
            }
        vis[t]=1;ans+=m;
        for(int j=1;j<=x;j++)
            if(!vis[j] && a[t][j]!=0)
                d[j]=min(d[j],a[t][j]);
    }
    return ans;
}

【2】kruskal

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 200000 + 10 ;
struct Node{
    int x,y,z;
}edge[maxn];
int f[maxn];
bool cmp(Node a,Node b){return a.z<b.z;}
int n,m,c,ans;
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void kruskal()
{
    int f1,f2,k(0);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
    {
        f1=find(edge[i].x);f2=find(edge[i].y);
        if(f1!=f2){
            ans=ans+edge[i].z;
            f[f1]=f2;
            if(++k==n-1) break;
        }
    }
    if(k<n-1) c=1;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
    sort(edge+1,edge+1+m,cmp);
    kruskal();
    printf( c ? "orz\n" : "%d\n",ans);
    return 0;
}

线段树

struct Node
{
    int l,r;
    int maxx;
}point[maxn * 4];
int x,y,a[maxn];
void Build_tree(int b,int l,int r)
{
    point[b].l=l,point[b].r=r;
    if(l==r) point[b].maxx=a[l];
    else
    {
        int mid = ( l + r ) / 2;
        Build_tree(b*2,l,mid);
        Build_tree(b*2+1,mid+1,r);
        point[b].maxx=max(point[2*b].maxx,point[b*2+1].maxx);
    }
}
int query(int b)
{
    if(x<=point[b].l && y>=point[b].r) return point[b].maxx;
    int mid = ( point[b].l + point[b].r ) / 2;
    int ans = -(1<<30);
    if(mid>=x) ans=max(ans,query(b*2));
    if(mid<y)  ans=max(ans,query(b*2+1));
    return ans;
}

树状数组

lca

void Deal_first(int u,int fa)
{
    Dep[u]=Dep[fa]+1;
    for(int i=0;i<=29;i++) f[u][i+1]=f[f[u][i]][i];
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        value[v]=value[u]+vi[i];
        f[v][0]=u;
        Deal_first(v,u);
    }
}
int LCA(int x,int y)
{
    if(Dep[x]<Dep[y]) swap(x,y);
    for(int i=30;i>=0;i--)
    {
        if(Dep[f[x][i]]>=Dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=30;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}

树的直径

void dfs(int u,int fa)
{
    for(int i=head[u];i;i=edge[i].next)
    {
        int  v=edge[i].to;
        if(v==fa) continue;
        dfs(v,u);
        fir[u]=max(fir[u],fir[v]);
        fir[u]=max(fir[u],dwn[u]+dwn[v]+1);
        dwn[u]=max(dwn[u],dwn[v]+1);
    }
}

 

tarjan强连通分量

int dfn[maxm],low[maxn],sccno[maxn],tim,ans[maxn];
int s[maxn],top,sec_cnt;
void dfs(int u)
{
    low[u]=dfn[u]=++tim;
    s[++top] = u;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        sec_cnt++;
        for(;;)
        {
            int x= s[top--];
            sccno[x] = sec_cnt;
            ans[sec_cnt]++;
            if(x==u) break;
        }
    }
}

kmp

void kmp()
{
    int j(0);
    for(int i=0;i<n;i++)
    {
        while(j>0 && B[j+1]!=A[i+1] ) j = p[j];
        if(B[j+1]==A[i+1]) j++;
        if(j==m)
        {
            printf("%d\n",i+1-m+1);
            j=p[j];
        }
    }
}
int main()
{
    scanf("%s %s",A+1,B+1);
    p[1]=0;
    n=strlen(A+1),m=strlen(B+1);
    int j(0);
    p[1]=0;
    for(int i=1;i<m;i++)
    {
        while(j>0 && B[j+1]!=B[i+1]) j=p[j];
        if(B[j+1]==B[i+1]) j++;
        p[i+1]=j;
    }
    kmp();
    return 0;
}

Trie字典树

Hash

树链剖分

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 30000 + 10 ; 
struct Node
{
    int next,to;
}edge[maxn * 4];
int head[maxn * 4],num,power[maxn * 4],v[maxn * 4];
int f[maxn*4],size[maxn*4],deep[maxn * 4],son[maxn * 4],rk[maxn * 4],top[maxn * 4],id[maxn *4];
void add(int x,int y)
{
    edge[++num].next=head[x];
    head[x]=num;
    edge[num].to=y;
}
struct Tree
{
    int left,right;
    int maxx,sum;
}tree[maxn*4];
int n,q;
void dfs1(int u,int fa)
{
    size[u]=1;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        f[v]=u;
        deep[v]=deep[u]+1;    
        dfs1(v,u);
        if(size[v]>size[son[u]])
            son[u]=v;
        size[u]+=size[v];
    }
}
int cnt;
void dfs2(int u)
{
    power[++cnt]=v[u];
//    top[u]=t;
    id[u]=cnt;
//    rk[cnt]=u;
    if(u==son[f[u]]) top[u]=top[f[u]];
    else              top[u]=u;
    if(son[u]) 
    dfs2(son[u]);
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=son[u] && v!=f[u])
            dfs2(v);
    }
}

void Build(int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    if(left==right)
    {tree[root].sum=tree[root].maxx=power[left]; return;}    
    int mid = (left+right)>>1;
    Build(root*2,left,mid);
    Build(root*2+1,mid+1,right);
    tree[root].sum=tree[root<<1].sum+tree[(root<<1)+1].sum;
    tree[root].maxx=max(tree[root<<1].maxx,tree[(root<<1)+1].maxx);
}

Tree query(int root,int left,int right)
{
    if(left<=tree[root].left && right>=tree[root].right)
        return tree[root];
        
    int mid =  tree[root].left + tree[root].right >>1;
    if(mid>=right) return query(root<<1,left,right);
    else if(mid<left) return query((root<<1)+1,left,right);
         else 
        {
             Tree ans,x=query(root<<1,left,mid),y=query((root<<1)+1,mid+1,right);
            ans.sum=x.sum+y.sum;
            ans.maxx=max(x.maxx,y.maxx);
            return ans;
        }
}

void modify(int pos,int x,int value)
{
    if(tree[pos].left==tree[pos].right)
        tree[pos].sum=tree[pos].maxx=value;
    else{
        int mid = (tree[pos].left+tree[pos].right)>>1;
        if(x<=mid) modify(pos*2,x,value);
        else modify(pos*2+1,x,value);
        tree[pos].sum=tree[pos*2+1].sum+tree[pos*2].sum;
        tree[pos].maxx=max(tree[pos*2+1].maxx,tree[pos*2].maxx);
    }
}

Tree sum(int x,int y)
{
    Tree ans;
    ans.sum=0;
    ans.maxx=-12345678;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        Tree k=query(1,id[top[x]],id[x]);
        ans.sum+=k.sum;
        ans.maxx=max(ans.maxx,k.maxx);
        x=f[top[x]];
    }
    if(deep[x]<deep[y]) swap(x,y);
    Tree k=query(1,id[y],id[x]);
    ans.sum+=k.sum;
    ans.maxx=max(ans.maxx,k.maxx);
    return ans;
}

int main()
{
    cin>>n;
    for(int i=1,a,b;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    for(int i=1;i<=n;i++) cin>>v[i];
    deep[1]=1;
    dfs1(1,0);
    dfs2(1);Build(1,1,cnt);
    cin>>q;
    while(q--)
    {
        int a,b;char c[20];
        scanf("%s %d%d",c,&a,&b);
        if(c[1]=='M') printf("%d\n",sum(a,b).maxx);
        if(c[1]=='S') printf("%d\n",sum(a,b).sum);
        if(c[1]=='H') modify(1,id[a],b);
    }
    return 0;
}

快速幂

int qpow(int a,int b)
{
    long long sum(1);
    while(b){
        if(b&1) sum=(long long)sum*a%mod;
        a=(long long)a*a%n;
        b>>=1;
    }
    return sum;
}

逆元

二分图匈牙利算法

bool found(int x)
{
    for(int i=1;i<=m;i++)
        if(map[x][i] && !used[i])
        {
            used[i]=1;
            if(!lair[i] || found(lair[i]))
            {
                lair[i]=x;
                return true;
            }
        }
    return false;
}
int main()
{
  for(int i=1;i<=n;i++) {
    memset(used,0,sizeof(used));
    if(found(i)) ans++;
  }

  return 0;
}

 

posted @ 2019-11-10 07:51  寒方  阅读(59)  评论(0编辑  收藏  举报