zoukankan      html  css  js  c++  java
  • 【计划】复习计划part 1

    前言

    因为经常考试,考着考着就开始气,明明想到/会做,但是模板不熟,或者哪个细节忘了,或者思想有点忘了,所以不敢写/写的很慢/写挂

    所以要记录一下要复习的内容,还是以时间为序,完成时间会在以后用红字在后面添上。

    复习大概是要包括 重温算法+熟练模板+写(不是板的)例题

    lca

    【happy那道题,想出来过后开心了半天,结果...敲不对】

    模板(注解的地方是踩得雷)

    poj1330

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define N 10100
    int n,t,x,y,cnt,root;
    int first[N],in[N],dep[N];
    int fa[N][20];
    struct email
    {
        int u,v;
        int nxt;
    }e[N*4];
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    
    void dfs(int u,int f)
    {
        for(int i=1;(1<<i)<=dep[u];i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(v==f)continue;
            fa[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v,u);
        }
    }
    
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        int k=dep[x]-dep[y];
        for(int i=0;(1<<i)<=k;i++)//1-->0 
            if(k&(1<<i))//手滑了 (i<<1)-->(1<<i)
                x=fa[x][i];
        if(x==y)return x;
        for(int i=19;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0]; 
    } 
    
    inline void init()
    {
        memset(in,0,sizeof(in));
        memset(dep,0,sizeof(dep));
        memset(first,0,sizeof(first));
        memset(fa,0,sizeof(fa));
        cnt=0;
    }
    
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            init();//不能省 
            scanf("%d",&n);
            for(int i=1;i<n;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                add(u,v);add(v,u);in[v]++;
            }
            for(int i=1;i<=n;i++)
                if(!in[i])
                {root=i;break;}
            dfs(root,0);
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
    }

     hdu2586

    #include<bits/stdc++.h>
    using namespace std;
    #define N 40400 
    int n,t,m,x,y,cnt;
    int first[N],dep[N],d[N];
    int fa[N][20];
    struct email
    {
        int u,v,w;
        int nxt;
    }e[N*4];
    inline void add(int u,int v,int w)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].v=v;e[cnt].u=u;e[cnt].w=w;
    }
    
    inline void init()
    {
        memset(in,0,sizeof(in));
        memset(dep,0,sizeof(dep));
        memset(first,0,sizeof(first));
        memset(fa,0,sizeof(fa));
        memset(d,0,sizeof(d));
        cnt=0;
    }
    
    void dfs(int u,int f)
    {
        for(int i=1;(1<<i)<=dep[u];i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v,w=e[i].w;
            if(v==f)continue;
            d[v]=d[u]+w;
            dep[v]=dep[u]+1;
            fa[v][0]=u;
            dfs(v,u);
        }
    }
    
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        int k=dep[x]-dep[y];
        for(int i=0;(1<<i)<=k;i++)
            if(k&(1<<i))
                x=fa[x][i];
        if(x==y)return x;
        for(int i=19;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d%d",&n,&m);
            for(int i=1;i<n;i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);add(v,u,w);in[v]++;
            }
            dfs(1,0);
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&x,&y);
                printf("%d
    ",d[x]+d[y]-2*d[lca(x,y)]);
            }
        }
    }

     不是板的例题:HDU4912

     结束 

    tarjan

    【也是因为happy那道题...看到环的第一想法,在脑子里默默过了一遍,发现好像不熟了?】

    首先是比较熟的有向图的强连通分量模板

    POJ2186 受欢迎的牛

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    using namespace std;
    #define N 20020
    int dfn[N],low[N],siz[N],col[N],vis[N],out[N],first[N];
    int n,m,cnt,tot,gro,ans;
    stack<int>s;
    struct email
    {
        int u,v;
        int nxt;
    }e[N*5];
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tot;
        s.push(u);vis[u]=1;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else
                if(vis[v])
                    low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            ++gro;
            while(1)
            {
                int t=s.top();s.pop();vis[t]=0;
                siz[gro]++;col[t]=gro;
                if(t==u)break;
            }
        }
        
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        for(int i=1;i<=n;i++)
            if(!col[i])
                tarjan(i);
        for(int i=1;i<=m;i++)
        {
            int u=e[i].u,v=e[i].v;
            if(col[u]!=col[v])
                out[col[u]]++;
        }
        for(int i=1;i<=gro;i++)
        {
            if(out[i]==0)//out[col[i]]==0;
            {
                if(ans)
                {
                    ans=0;
                    break;
                }
                ans=i;
            }
        }
        printf("%d
    ",siz[ans]);
        
    }

     HDU 1269

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    using namespace std;
    #define N 10100
    #define M 100100
    int vis[N],dfn[N],low[N],col[N],first[N];
    int n,m,cnt,tot,gro,flag;
    stack<int>s;
    struct email
    {
        int u,v;
        int nxt;
    }e[M*2];
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    
    inline void init()
    {
        cnt=0,tot=0,gro=0;
        memset(first,0,sizeof(first));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(col,0,sizeof(col));
    }
    
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tot;
        s.push(u);vis[u]=1;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else
                if(vis[v])
                    low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            ++gro;
            while(1)
            {
                int t=s.top();s.pop();vis[t]=0;    
                col[t]=gro;
                if(t==u)break;
            }
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)&&n)
        {
            init();
            for(int i=1;i<=m;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                add(u,v);
            }
            for(int i=1;i<=n;i++)
                if(!col[i])
                    tarjan(i);
            if(gro==1)
                printf("Yes
    ");
            else
                printf("No
    ");
        }
    }

     难受啊,没想到割边割点对我来说比缩点更困难

    终于割边的板子出来了

    luogu 3388

    给自己写一点reminders吧

    1.根据定义,只有一个子节点的根不是割点,所以dfs时,分是根或者不是根,结束dfs当前节点前补回这个u可能是根且是割点的情况

    2.割点数量最后统计,不要懒得打那一个for循,在过程中统计包挂

    3.割点是>=

    4.图不一定联通

    5.不需要判v==fa,因为dfn能阻断已经访问过的点

    6.如果v不能回到比dfn[u]小的点,说明u是割点,而不是v(只能回到u点,u也是割点)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100100
    int n,m,cnt,tot,num,root,child;
    int dfn[N],low[N],cut[N],first[N];
    struct email
    {
        int u,v;
        int nxt;
    }e[N*4];
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    
    inline void tarjan(int u)
    {
        dfn[u]=low[u]=++tot;child=0;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]&&u!=root) 
                    cut[u]=1;//,num++
                if(u==root)child++;
            }
            else
                low[u]=min(low[u],dfn[v]);
        }
        if(child>1&&u==root)cut[u]=1;//,num++
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                root=i,tarjan(i);
        for(int i=1;i<=n;i++)
            if(cut[i])
                num++;
            printf("%d
    ",num);        
        for(int i=1;i<=n;i++)
            if(cut[i])
                printf("%d ",i);
        return 0;
     } 

    今晚商量了一下停课的事情,割边终于也出炉了,tarjan这一块儿终于可以放心地做题了

    没测过,只自己手造了一组,假装是对的吧【找不到模板题测啊】

    又是可爱的reminders

    1.这个不需要判根,但是需要严格防止搜爆,比起割点,多传参了一个u。

    2.有一句  v!=fa&&dfn[v]<dfn[u],双重保险吧,我也不知道哪句必要,干脆都写

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100100
    int dfn[N],low[N],first[N];
    int n,m,cnt,tot,num;
    struct email
    {
        int u,v;
        int nxt;
    }e[N*4],cut[N*4]; 
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    
    inline void tarjan(int u,int fa)
    {
    
        dfn[u]=low[u]=++tot;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u])
                    cut[++num]=e[i];
            }
            else
                if(v!=fa&&dfn[v]<dfn[u])
                    low[u]=min(low[u],dfn[v]);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i,0);
        for(int i=1;i<=num;i++)
        {
            int u=cut[i].u,v=cut[i].v;
            printf("%d-->%d
    ",u,v);
        }
        return 0;
    }
    /*
    8 9
    1 2
    1 3
    1 4
    2 4
    3 4
    4 5
    4 6
    6 8
    6 7
    */

    敲熟了 完结

    线段树

    【脑抽,t1去敲线段树,关键是还敲挂了】

    模板

    注解的地方是踩雷区。总结一下感觉还是对lazy的理解不深刻

    合并区间的时候脑抽一下,lazy其实对于当前节点是执行了加权操作,只是暂时不修改更多的儿子罢了..

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100100
    #define ll long long
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define mid (t[p].l+t[p].r>>1)
    ll n,m,op;
    ll a[N];
    struct email
    {
        ll l,r,sum,lazy;
    }t[N*4];
    
    inline void pushnow(ll p,ll v)
    {
        t[p].sum+=(t[p].r-t[p].l+1)*v;
        t[p].lazy+=v; 
    }
    
    inline void pushdown(ll p)
    {
        if(t[p].lazy)
        {
            pushnow(lc,t[p].lazy);
            pushnow(rc,t[p].lazy);
            t[p].lazy=0;
        }
    }
    
    inline void pushup(ll p)
    {
        t[p].sum=t[lc].sum+t[rc].sum;
        //t[p].sum+=t[lc].sum+t[rc].sum;
    }
    
    inline void build(ll p,ll l,ll r)
    {
        t[p].l=l;t[p].r=r;
        if(l==r)
        {
            t[p].sum=a[l];
            return ;
        }
        ll bmid=l+r>>1;
        build(lc,l,bmid);build(rc,bmid+1,r);
        pushup(p);
    }
    
    inline void update(ll p,ll ql,ll qr,ll v)
    {
        if(ql<=t[p].l&&qr>=t[p].r)
        {
            pushnow(p,v);//t[p].sum+=v;t[p].lazy+=v;
            return ; 
        }
        pushdown(p);
        if(ql<=mid)update(lc,ql,qr,v);
        if(qr>mid)update(rc,ql,qr,v);
        pushup(p);
    }
    
    inline ll query(ll p,ll ql,ll qr)
    {
        ll ret=0;
        if(ql<=t[p].l&&qr>=t[p].r)
            return t[p].sum;
        pushdown(p);
        if(ql<=mid)    ret+=query(lc,ql,qr);
        if(qr>mid)    ret+=query(rc,ql,qr);
        return ret; 
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(ll i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        build(1,1,n);
        for(ll i=1;i<=m;i++)
        {
            scanf("%lld",&op);
            if(op==1)
            {
                ll x,y,v;
                scanf("%lld%lld%lld",&x,&y,&v);
                update(1,x,y,v);
            }
            if(op==2)
            {
                ll x,y;
                scanf("%lld%lld",&x,&y);
                printf("%lld
    ",query(1,x,y));
            }
        }
        return 0;
    }

     例题

    结束

    树状数组

    【敲挂了线段树过后就敲了树状数组,又挂了。。】

    模板

    区间修改单点查询(区间查询的我选择用线段树...怕加加减减混了影响心态)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100100
    int n,m,op;
    int a[N],b[N];
    inline int lowbit(int x)
    {
        return x&(-x);    
    } 
    
    inline void add(int x,int y)
    {
        for(;x<=n;x+=lowbit(x))
            b[x]+=y;
    }
    
    inline int query(int x)
    {
        int ret=0;
        for(;x;x-=lowbit(x))
            ret+=b[x];
        return ret;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op);
            if(op==1)
            {
                int l,r,v;
                scanf("%d%d%d",&l,&r,&v);
                add(l,v);add(r+1,-v);
            }
            if(op==2)
            {
                int k;
                scanf("%d",&k);
                printf("%d
    ",query(k)+a[k]);
            }
        }
        return 0;
    }

     例题,逆序对

    结束

    树的直径

    【花花森林虽然虚惊一场,但是树的直径确实只是知道思想,还是得去敲一敲】

    dp求直径模板

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100010
    int n,m,cnt,ans;
    int d[N],vis[N],first[N];
    struct email
    {
        int u,v,w;
        int nxt;
    }e[N*4];
    inline void add(int u,int v,int w)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;
    }
    void dp(int u)
    {
        vis[u]=1;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v,w=e[i].w;
            if(vis[v])continue;
            dp(v);
            ans=max(ans,d[v]+d[u]+w);
            d[u]=max(d[u],d[v]+w);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            char dir[3];
            scanf("%d%d%d%s",&u,&v,&w,dir);
            add(u,v,w);add(v,u,w);
        }
        dp(1);
        printf("%d
    ",ans);
        return 0;
    }

    两次dfs

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100010
    int n,m,cnt,ans1,ans2;
    int d[N],vis[N],first[N];
    struct email
    {
        int u,v,w;
        int nxt;
    }e[N*4];
    inline void add(int u,int v,int w)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;
    }
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v,w=e[i].w;
            if(vis[v])continue;
            d[v]=d[u]+w;
            dfs(v);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            char dir[3];
            scanf("%d%d%d%s",&u,&v,&w,dir);
            add(u,v,w);add(v,u,w);
        }
        dfs(1);
        for(int i=1;i<=n;i++)
            if(ans1<d[i])
                ans1=d[i],ans2=i;
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        dfs(ans2);
        for(int i=1;i<=n;i++)
            ans1=max(ans1,d[i]);
        printf("%d
    ",ans1);
        return 0;
    }

    逆元

    【到现在也不是很懂,花花森林的逆元为什么不能用费马小定理啊..还是我写挂了的原因??】

    终于填上此坑了!!

    四种方法求逆元

    值得拥有!!!证明都很简单,手玩一下吧。玩不出来就背呗。

    完结

    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    数据库的字符集和校对集
    登录和退出Mysql
    启动mysql服务器
    Numpy
    如何用navicat导入数据?
    MySQL不能连接本地数据库10061
    使用navicat连接Mysql8.0出现2059错误
    leetcode笔记11 First Unique Character in a String
    leetcode笔记10 Intersection of Two Arrays(求交集)
    leetcode笔记9 Move Zeroes
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9653359.html
Copyright © 2011-2022 走看看