zoukankan      html  css  js  c++  java
  • NOIp知识集合 By cellur925

    基本算法

    • 快速幂
     1 ll ksm(ll a,ll b)
     2 {
     3     ll ans=1;
     4     while(b)
     5     {
     6         if(b&1) ans=ans*a%p;
     7         b>>=1;
     8         a=a*a%p;
     9     }
    10     return ans;
    11 } 
    ksm
    • 64位大整数乘法
     1 ll mul(ll a,ll b)
     2 {
     3     ll ans=0;
     4     while(b)
     5     {
     6         if(b&1) ans=(ans+a)%p;
     7         b>>=1;
     8         a=a*2%p;
     9     }
    10     return ans;
    11 }
    mul
    • 离散化
    1     for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
    2     sort(b+1,b+1+n);
    3     int cnt=unique(b+1,b+1+n)-(b+1);
    4     for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; 
    discrete
    • 归并排序求逆序对
     1 void mergesort(int l,int r)
     2 {
     3     if(l==r) return ;
     4     int mid=(l+r)>>1;
     5     mergesort(l,mid);
     6     mergesort(mid+1,r);
     7     int i=l,j=mid+1,k=l-1;
     8     while(i<=mid&&j<=r)
     9     {
    10         if(a[i]<=a[j]) b[++k]=a[i],i++;
    11         else b[++k]=a[j],j++,(ans+=mid-i+1)%=moder;
    12     }
    13     while(i<=mid) b[++k]=a[i],i++;
    14     while(j<=r) b[++k]=a[j],j++;
    15     for(int qwq=l;qwq<=r;qwq++) a[qwq]=b[qwq];
    16 }
    mergesort
    • 全排列
     1 void dfs(int x)
     2 {
     3     for(int i=1;i<=n;i++)
     4         if(!vis[i])
     5         {
     6             seq[x]=i;
     7             vis[i]=1;
     8             if(x==n) work();
     9             else dfs(x+1);
    10             vis[i]=0;
    11         }
    12 }
    Permutation
    • ST表
     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cmath>
     4 
     5 using namespace std;
     6 
     7 int n,m;
     8 int st[100090][30];
     9 
    10 int sta(int l,int r)
    11 {
    12     int k=log2(r-l+1);
    13     return max(st[l][k],st[r-(1<<k)+1][k]);
    14 }
    15 
    16 int main()
    17 {
    18     scanf("%d%d",&n,&m);
    19     for(int i=1;i<=n;i++) scanf("%d",&st[i][0]);
    20     for(int j=1;j<=30;j++)
    21         for(int i=1;i+(1<<j)-1<=n;i++)
    22             st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    23     for(int i=1;i<=m;i++)
    24     {
    25         int l=0,r=0;
    26         scanf("%d%d",&l,&r);
    27         printf("%d
    ",sta(l,r));
    28     }
    29     return 0;
    30 }
    ST Table
    • 两种二分
     1 while(l<r)
     2 {
     3     int mid=(l+r)>>1;
     4     if(check(mid)) r=mid;
     5     else l=mid+1;
     6 }
     7 while(l<r)
     8 {
     9     int mid=(l+r+1)>>1;
    10     if(check(mid)) r=mid-1;
    11     else l=mid;
    12 }
    整数域二分
    1 double eps=1e-8;
    2 while(l+eps<r)
    3 {
    4     double mid=(l+r)/2;
    5     if(check(mid)) r=mid;
    6     else l=mid;
    7 }
    实数域二分
     1 void Recantor(ll x)
     2 {
     3     memset(vis,0,sizeof(vis));
     4     x--;
     5     int j=0;
     6     for(int i=1;i<=n;i++)
     7     {
     8         ll t=x/fac[n-i];
     9         for(j=1;j<=n;j++)
    10             if(!vis[j])
    11             {
    12                 if(!t) break;
    13                 t--;
    14             }
    15         printf("%d ",j);
    16         vis[j]=1;
    17         x%=fac[n-i]; 
    18     }
    19     printf("
    ");
    20 }
    21 
    22 ll cantor()
    23 {
    24     ll ans=1;
    25     for(int i=1;i<=n;i++)
    26     {
    27         int tot=0;
    28         for(int j=i+1;j<=n;j++)
    29             if(a[j]<a[i]) tot++;
    30         ans+=1ll*tot*fac[n-i];
    31     }
    32     return ans;
    33 }
    Cantor&Recantor

    其他算法

    • 莫队算法(不带修)
     1 bool cmp(query a,query b)
     2 {
     3     return (a.l/block)^(b.l/block) ? a.l<b.l : (((a.l/block)&1) ? a.r<b.r : a.r>b.r);
     4 }//奇偶块排序
     5 
     6 
     7 
     8     block=sqrt(n);
     9     for(int i=1;i<=n;i++) scanf("%d",&seq[i]);
    10     for(int i=1;i<=m;i++)
    11     {
    12         scanf("%d%d",&ask[i].l,&ask[i].r);
    13         ask[i].id=i;
    14         ask[i].in=ask[i].l/block;
    15     }
    16     sort(ask+1,ask+1+m,cmp);
    17     for(int i=1;i<=m;i++)
    18     {
    19         int l=ask[i].l,r=ask[i].r;
    20         while(posl<l) remove(posl++);
    21         while(posr>r) remove(posr--);
    22         while(posl>l) add(--posl);
    23         while(posr<r) add(++posr);
    24         ans[ask[i].id]=noww;
    25     }
    26     for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    Mo's Algorithm

    数学

    • 预处理阶乘和处理逆元求组合数
     1 ll exgcd(ll a,ll b,ll &x,ll &y)
     2 {
     3     if(b==0)  
     4     {  
     5           x=1;  
     6           y=0;  
     7           return a;  
     8     }  
     9     int gu=exgcd(b,a%b,x,y);  
    10     int t=x;  
    11     x=y;  
    12     y=t-a/b*y;  
    13     return gu;  
    14 
    15 }
    16 
    17 ll niyuan(ll hu)
    18 {
    19     x=0,y=0;
    20     ll tmp=exgcd(hu,p,x,y);
    21     return (x+p)%p;
    22 }
    23 
    24 ll C(ll k,ll m)
    25 {
    26     ll up=fac[k]%p;
    27     ll down=fac[m]%p*fac[k-m]%p;
    28     ll ans=up*niyuan(down)%p;
    29     return ans;
    30 }
    31 
    32 void pre()
    33 {
    34     fac[0]=1;
    35     for(int i=1;i<=n+1;i++)
    36         fac[i]=(ll)fac[i-1]*i%p;
    37 }
    Combination
    • 杨辉三角求组合数

    1     C[0][0]=1;C[1][1]=1;
    2     for(int i=1;i<=n;i++) C[i][0]=1,C[i][i]=1;
    3     for(int i=1;i<=n;i++)
    4         for(int j=1;j<=i;j++)
    5             (C[i][j]=C[i-1][j]+C[i-1][j-1])%=moder;
    Yang's triangle

    数据结构

    • $vector$实现普通平衡树 慎用!!!
     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 
     5 using namespace std;
     6 
     7 int n;
     8 vector<int>v;
     9 
    10 int main()
    11 {
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;i++)
    14     {
    15         int op=0,x=0;
    16         scanf("%d%d",&op,&x);
    17         if(op==1) v.insert(upper_bound(v.begin(),v.end(),x),x);
    18         else if(op==2) v.erase(lower_bound(v.begin(),v.end(),x));
    19         else if(op==3) printf("%d
    ",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
    20         else if(op==4) printf("%d
    ",v[x-1]);
    21         else if(op==5) printf("%d
    ",*--lower_bound(v.begin(),v.end(),x));
    22         else if(op==6) printf("%d
    ",*upper_bound(v.begin(),v.end(),x));
    23     }
    24     return 0;
    25 }
    26 /*
    27 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    28 1. 插入x数
    29 2. 删除x数(若有多个相同的数,因只删除一个)
    30 3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    31 4. 查询排名为x的数
    32 5. 求x的前驱(前驱定义为小于x,且最大的数)
    33 6. 求x的后继(后继定义为大于x,且最小的数)
    34 */
    Balanced Tree By vector

    图论

    • Floyd算法。复杂度$O(n^3)$
     1     memset(dis,0x3f,sizeof(dis));
     2     for(int i=1;i<=v;i++) dis[i][i]=0,dis[0][i]=0;//这一步很重要
     3     for(int i=1;i<=e;i++)
     4     {
     5         int x=0,y=0,z=0;
     6         scanf("%d%d%d",&x,&y,&z);
     7         dis[x][y]=min(dis[x][y],z);
     8         dis[y][x]=min(dis[y][x],z);
     9     }
    10     for(int kk=1;kk<=v;kk++)
    11         for(int i=1;i<=v;i++)
    12             for(int j=1;j<=v;j++)
    13                 dis[i][j]=min(dis[i][j],dis[i][kk]+dis[kk][j]);
    floyd
    • Dijkstra+堆优化。复杂度$O(mlogn)$。稠密图优。好像不能用来跑最长路诶(
     1 void dijkstra()
     2 {
     3     priority_queue<pair<int,int> >q;
     4     memset(dis,0x3f,sizeof(dis));
     5     dis[s]=0;q.push(make_pair(0,s));
     6     while(!q.empty())
     7     {
     8         int u=q.top().second;q.pop();
     9         if(vis[u]) continue;
    10         vis[u]=1;
    11         for(int i=head[u];i;i=edge[i].next)
    12         {
    13             int v=edge[i].to;
    14             if(dis[v]>dis[u]+edge[i].val)
    15             {
    16                 dis[v]=dis[u]+edge[i].val;
    17                 q.push(make_pair(-dis[v],v));
    18             }
    19         }
    20     }
    21 }
    Dijkstra+Heap
    • spfa过世算法复杂度理解为$O(nm)$。但稀疏图$O(km)$。
     1 void spfa()
     2 {
     3     memset(dis,0x3f,sizeof(dis));
     4     queue<int>q;
     5     q.push(s),vis[s]=1,dis[s]=0;
     6     while(!q.empty())
     7     {
     8         int u=q.front();q.pop();
     9         vis[u]=0;
    10         for(int i=head[u];i;i=edge[i].next)
    11         {
    12             int v=edge[i].to;
    13             if(dis[v]>dis[u]+edge[i].val)
    14             {
    15                 dis[v]=dis[u]+edge[i].val;
    16                 if(!vis[v]) q.push(v),vis[v]=1;
    17             }
    18         }
    19     }
    20 }
    spfa
    • 判断树上两路径是否相交

    *  题目:LuoguP3398仓鼠找sugar / 计蒜客NOIP提高组模拟一试T2 敌对势力 / hihocoder 11D(题目找不到了==可以看这位dalao的博客

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<queue>
      4 #include<cmath>
      5 #define maxn 100090 
      6 
      7 using namespace std;
      8 
      9 int n,m,tot,t;
     10 int head[maxn],d[maxn],f[maxn][20];
     11 struct node{
     12     int to,next;
     13 }edge[maxn*2];
     14 
     15 void add(int x,int y)
     16 {
     17     edge[++tot].to=y;
     18     edge[tot].next=head[x];
     19     head[x]=tot;
     20 }
     21 
     22 void LCA_prework()
     23 {
     24     queue<int>q;
     25     q.push(1);d[1]=1;
     26     while(!q.empty())
     27     {
     28         int u=q.front();q.pop();
     29         for(int i=head[u];i;i=edge[i].next)
     30         {
     31             int v=edge[i].to;
     32             if(d[v]) continue;
     33             d[v]=d[u]+1;
     34             f[v][0]=u;
     35             for(int j=1;j<=t;j++)
     36                 f[v][j]=f[f[v][j-1]][j-1];
     37             q.push(v);
     38         }
     39     }
     40 }
     41 
     42 int LCA(int x,int y)
     43 {
     44     if(d[x]>d[y]) swap(x,y);
     45     for(int i=t;i>=0;i--)
     46         if(d[f[y][i]]>=d[x]) y=f[y][i];
     47     if(x==y) return x;
     48     for(int i=t;i>=0;i--)
     49         if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
     50     return f[x][0];
     51 }
     52 
     53 int main()
     54 {
     55     scanf("%d%d",&n,&m);
     56     t=log2(n)+1;
     57     for(int i=1;i<=n-1;i++)
     58     {
     59         int x=0,y=0;
     60         scanf("%d%d",&x,&y);
     61         add(x,y);add(y,x);
     62     }
     63     LCA_prework();
     64     for(int i=1;i<=m;i++)
     65     {
     66         int a=0,b=0,c=0,e=0;
     67         scanf("%d%d%d%d",&a,&b,&c,&e);
     68         int Chemist=LCA(a,b);
     69         int cellur=LCA(c,e);
     70         if(Chemist==cellur)
     71         {
     72             printf("NO
    ");
     73             continue;
     74         }
     75         if(d[Chemist]>d[cellur])
     76         {
     77             if(LCA(Chemist,c)==Chemist||LCA(Chemist,e)==Chemist)
     78             { 
     79                 printf("NO
    ");
     80                 continue;
     81             }
     82             else
     83             {//没有相交输出yes 
     84                 printf("YES
    ");
     85                 continue;
     86             }
     87         }
     88         else
     89         {
     90             if(LCA(cellur,a)==cellur||LCA(cellur,b)==cellur)
     91             {
     92                 printf("NO
    ");
     93                 continue;
     94             }
     95             else
     96             {
     97                 printf("YES
    ");
     98                 continue;
     99             }
    100         }
    101     }
    102     
    103     return 0;
    104 }
    View Code
    • 最短路计数
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    
    using namespace std;
    typedef long long ll;
    
    int n,m,fake;
    int vis[2090],dis[2090];
    ll f[2090];
    int e[2090][2090];
    
    void spfa()
    {
        memset(dis,63,sizeof(dis));
        fake=dis[233];
        queue<int>q;
        q.push(1);vis[1]=1;dis[1]=0;f[1]=1;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            if(u==n) continue;
            for(int i=1;i<=n;i++)
            {
                if(dis[i]==dis[u]+e[u][i])
                    f[i]+=f[u];
                if(dis[i]>dis[u]+e[u][i])
                {
                    dis[i]=dis[u]+e[u][i];
                    f[i]=f[u];
                }
                if(f[i]&&!vis[i]) vis[i]=1,q.push(i);  
            }
            f[u]=0;
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(e,63,sizeof(e));
        for(int i=1;i<=m;i++)
        {
            int x=0,y=0,z=0;
            scanf("%d%d%d",&x,&y,&z);
            e[x][y]=min(e[x][y],z);
        }
        spfa();
        if(fake==dis[n]) printf("No answer");
        else printf("%d %lld",dis[n],f[n]);
        return 0;
    }
    View Code

    以上是过世算法$spfa$,现在我来为大家表演一下$dijkstra$。(搬运逛公园的30部分分)dij不用清空,非常优秀。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #include<cstring>
     5 #define maxn 100090
     6 
     7 using namespace std;
     8 typedef long long ll;
     9 
    10 int T,n,m,k,tot;
    11 int head[maxn];
    12 bool vis[maxn];
    13 ll moder,f[maxn],dis[maxn];
    14 struct node{
    15     int to,next,val;
    16 }edge[maxn<<2];
    17 
    18 void add(int x,int y,int z)
    19 {
    20     edge[++tot].to=y;
    21     edge[tot].next=head[x];
    22     head[x]=tot;
    23     edge[tot].val=z;
    24 }
    25 
    26 void Clear()
    27 {
    28     tot=0;
    29     memset(head,0,sizeof(head));
    30     memset(vis,0,sizeof(vis));
    31     memset(f,0,sizeof(f));
    32 }
    33 
    34 void dijkstra()
    35 {
    36     priority_queue<pair<ll,int> >q;
    37     for(int i=1;i<=n;i++) dis[i]=3e9;
    38     q.push(make_pair(0,1));dis[1]=0;f[1]=1;
    39     while(!q.empty())
    40     {
    41         int u=q.top().second;q.pop();
    42         if(vis[u]) continue;
    43         vis[u]=1;
    44         for(int i=head[u];i;i=edge[i].next)
    45         {
    46             int v=edge[i].to;
    47             if(dis[v]>dis[u]+edge[i].val)
    48             {
    49                 dis[v]=dis[u]+edge[i].val;
    50                 q.push(make_pair(-dis[v],v));
    51                 (f[v]=f[u])%=moder;
    52             }
    53             else if(dis[v]==dis[u]+edge[i].val)
    54                 (f[v]+=f[u])%=moder;
    55         }
    56     }
    57 }
    58 
    59 int main()
    60 {
    61     scanf("%d",&T);
    62     while(T--)
    63     {
    64         scanf("%d%d%d%lld",&n,&m,&k,&moder);
    65         for(int i=1;i<=m;i++)
    66         {
    67             int x=0,y=0,z=0;
    68             scanf("%d%d%d",&x,&y,&z);
    69             add(x,y,z);
    70         }
    71         dijkstra();
    72     //    if(dis[n]==3e9) printf("-1");
    73         printf("%lld
    ",f[n]);
    74         //for(int i=1;i<=n;i++) printf("%lld ",dis[i]);
    75         Clear();
    76     }
    77     return 0;
    78 }
    Counting
    • kruskal算法求最小生成树:基于边。比较好理解,先对所有边进行排序,用并查集维护联通关系。复杂度为$O(mlogm)$。(其实不用找到n-1条边就退出...)
     1 /*
     2 最小生成树Kruskal算法
     3 快排权值+并查集看是否连通
     4 */ 
     5 #include<cstdio>
     6 #include<algorithm>
     7 
     8 using namespace std;
     9 
    10 int n,m,cnt,ans;
    11 int fa[5090];
    12 struct node{
    13     int f,t,w;
    14 }edge[400090];
    15 
    16 bool cmp(node a,node b)
    17 {
    18     return a.w<b.w;
    19 }
    20 
    21 int getf(int x)
    22 {
    23     if(x==fa[x]) return x;
    24     return fa[x]=getf(fa[x]);
    25 }
    26 
    27 int main()
    28 {
    29     scanf("%d%d",&n,&m);
    30     for(int i=1;i<=m;i++)
    31         scanf("%d%d%d",&edge[i].f,&edge[i].t,&edge[i].w);
    32     for(int i=1;i<=n;i++) fa[i]=i;
    33     sort(edge+1,edge+1+m,cmp);
    34     for(int i=1;i<=m;i++)
    35     {
    36         if(cnt==n-1) break;
    37         int pp=getf(edge[i].f);
    38         int qq=getf(edge[i].t);
    39         if(pp==qq) continue;
    40         fa[qq]=pp;
    41         cnt++;
    42         ans+=edge[i].w;
    43     }
    44     if(cnt<n-1) printf("orz");
    45     else printf("%d
    ",ans);
    46     return 0;
    47 }
    Kruskal
    • Prim算法求最小生成树:基于点,逐步扩展。随便找一个点作为起点,设$dis$为添加了这个点需要增加的边权,然后每次在尚未被进入生成树的节点中寻找最小的$dis$,记录它的位置,这一次就把他加入生成树,并更新其他点的$dis$。复杂度$O(n^2)$。注意是否$vis$。
     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define maxn 5090
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 
     9 int n,m,tot;
    10 ll ans;
    11 int head[maxn],dis[maxn],vis[maxn];
    12 struct node{
    13     int to,next,val;
    14 }edge[400090];
    15 
    16 void add(int x,int y,int z)
    17 {
    18     edge[++tot].to=y;
    19     edge[tot].next=head[x];
    20     head[x]=tot;
    21     edge[tot].val=z;
    22 }
    23 
    24 void prim()
    25 {
    26     memset(dis,127,sizeof(dis));
    27     dis[1]=0;
    28     for(int k=1;k<=n;k++)
    29     {
    30         int u=-1,sta=0x3f3f3f3f;
    31         for(int i=1;i<=n;i++)
    32             if(dis[i]<sta&&!vis[i]) sta=dis[i],u=i;
    33         if(u==-1) {printf("orz
    ");exit(0);}
    34         ans+=dis[u];
    35         vis[u]=1;
    36         for(int i=head[u];i;i=edge[i].next)
    37         {
    38             int v=edge[i].to;
    39             if(vis[v]) continue;
    40             dis[v]=min(dis[v],edge[i].val);
    41         }
    42     }
    43 }
    44 
    45 int main()
    46 {
    47     scanf("%d%d",&n,&m);
    48     for(int i=1;i<=m;i++)
    49     {
    50         int x=0,y=0,z=0;
    51         scanf("%d%d%d",&x,&y,&z);
    52         add(x,y,z);add(y,x,z);
    53     }
    54     prim();
    55     printf("%d
    ",ans);
    56     return 0;
    57 } 
    Prim
    • 树的直径方法一:两遍bfs/dfs【不能处理有负权边情况】【记录路径】
     1 int bfs(int x)
     2 {
     3     queue<int>q;
     4     memset(d,0x3f,sizeof(d));
     5     memset(pre,0,sizeof(pre));
     6     fake=d[233];
     7     q.push(x);d[x]=0;
     8     while(!q.empty())
     9     {
    10         int u=q.front();q.pop();
    11         for(int i=head[u];i;i=edge[i].next)
    12         {
    13             int v=edge[i].to;
    14             if(d[v]==fake) q.push(v),pre[v]=i,d[v]=d[u]+1;
    15         }
    16     }
    17     int top=x;
    18     for(int i=1;i<=n;i++)
    19         if(d[i]>d[top]) top=i;
    20     return top; 
    21 }
    22 int get_d()
    23 {
    24     p=bfs(1);
    25     p=bfs(p);
    26     return d[p];
    27 }
    Tree's Diameter/BFS
    • 树的直径方法二:树形dp
     1 void Treedp(int u)
     2 {
     3     vis[u]=1;
     4     for(int i=head[u];i;i=edge[i].next)
     5     {
     6         int v=edge[i].to;
     7         if(vis[v]) continue;
     8         Treedp(v);
     9         ans=max(ans,f[x]+f[y]+edge[i].val)
    10         f[x]=max(f[x],f[y]+edge[i].val);
    11     }
    12 }
    Tree's Diameter/Treedp
    • 强连通分量/缩点(in有向图)
     1 void tarjan(int u)
     2 {
     3     dfn[u]=low[u]=++dfs_clock;
     4     st.push(u);
     5     for(int i=head[u];i;i=edge[i].next)
     6     {
     7         int v=edge[i].to;
     8         if(!dfn[v])
     9         {
    10             tarjan(v);
    11             low[u]=min(low[u],low[v]);
    12         }
    13         else if(!scc[v]) low[u]=min(low[u],dfn[v]);
    14     }
    15     if(low[u]==dfn[u])
    16     {
    17         scc_cnt++;
    18         while(1)
    19         {
    20             int x=st.top();st.pop();
    21             scc[x]=scc_cnt;
    22             if(x==u) break;
    23         }
    24     }
    25 }
    26 —————————————————————————————————————
    27     for(int i=1;i<=n;i++)//在主程序中
    28         if(!dfn[i]) tarjan(i);
    29     for(int x=1;x<=n;x++)
    30         for(int i=head[x];i;i=edge[i].next)
    31         {
    32             int y=edge[i].to;
    33             if(scc[x]!=scc[y])
    34                 ADD(scc[x],scc[y]);
    35         }
    tarjan1
    • 树上倍增求LCA

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #include<cmath>
     5 #define maxn 500090
     6 
     7 using namespace std;
     8 
     9 int n,m,s,tot,t;
    10 int d[maxn],head[maxn],f[maxn][31];
    11 struct node{
    12     int to,next;
    13 }edge[maxn<<1];
    14 
    15 void add(int x,int y)
    16 {
    17     edge[++tot].to=y;
    18     edge[tot].next=head[x];
    19     head[x]=tot;
    20 }
    21 
    22 void init()
    23 {
    24     queue<int>q;
    25     q.push(s);d[s]=1;
    26     while(!q.empty())
    27     {
    28         int u=q.front();q.pop();
    29         for(int i=head[u];i;i=edge[i].next)
    30         {
    31             int v=edge[i].to;
    32             if(d[v]) continue;
    33             d[v]=d[u]+1;
    34             f[v][0]=u;
    35             for(int j=1;j<=t;j++)
    36                 f[v][j]=f[f[v][j-1]][j-1];
    37             q.push(v);
    38         }
    39     }
    40 }
    41 
    42 int lca(int x,int y)
    43 {
    44     if(d[x]<d[y]) swap(x,y);
    45     for(int i=t;i>=0;i--)    
    46         if(d[f[x][i]]>=d[y]) x=f[x][i];
    47     if(x==y) return x;
    48     for(int i=t;i>=0;i--)
    49         if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    50     return f[x][0];
    51 }
    52 
    53 int main()
    54 {
    55     scanf("%d%d%d",&n,&m,&s);
    56     t=log2(n)+1;
    57     for(int i=1;i<=n-1;i++)
    58     {
    59         int x=0,y=0;
    60         scanf("%d%d",&x,&y);
    61         add(x,y),add(y,x);
    62     }
    63     init();
    64     for(int i=1;i<=m;i++)
    65     {
    66         int x=0,y=0;
    67         scanf("%d%d",&x,&y);
    68         printf("%d
    ",lca(x,y));
    69     }
    70     return 0;
    71 } 
    LCA

    字符串

    • $trie$树
     1 tot=0;
     2 void insert()
     3 {
     4     int p=0;
     5     int len=strlen(tmp+1);
     6     for(int i=1;i<=len;i++)
     7     {
     8         int qwq=tmp[i]-'0';
     9         if(!trie[p][qwq]) trie[p][qwq]=++tot;
    10         p=trie[p][qwq];
    11     }
    12 }
    trie--insert
    •  最小表示法
     1 void work()
     2 {
     3     n=strlen(str+1);ans=0;
     4     for(int i=1;i<=n;i++) str[n+i]=str[i];
     5     int i=1,j=2,k;
     6     while(i<=n&&j<=n)
     7     {
     8         for(k=0;k<=n&&str[i+k]==str[j+k];k++);
     9         if(k>=n) break;
    10         if(str[i+k]>str[j+k])
    11         {i=i+k+1;if(i==j) i++;}
    12         else
    13         {j=j+k+1;if(i==j) j++;}
    14     }
    15     ans=min(i,j);
    16     printf("%d
    ",ans);
    17 }
    18 //注意数组开二倍+
    Minimal Expression

    其他技巧

    srand(time(NULL));
    • 生成数据的批处理文件($bat$)
     1 @echo off
     2 :loop
     3 
     4 rand.exe
     5 
     6 baoli.exe
     7 
     8 sol.exe
     9 
    10 fc baoli.out sol.out
    11 
    12 if not errorlevel 1 goto loop
    13 
    14 pause 
    15 
    16 goto loop
    dp.bat
    • 生成数据
    1 int random(int lim)
    2 {
    3     return (unsigned long long)rand()*rand()%lim; 
    4 }
    5 
    6 
    7 调用时:int x=random(100)+1;
    rand

    看到小数据范围:暴搜 全排列 二进制枚举  状压

    $O(n^3)$:考虑枚举区间?

  • 相关阅读:
    SQL 操作总结
    WaitHandle.WaitOne的第二参数
    java泛型测试
    生成商品静态页的类和方法
    CodeSmith4.1在控制台根据模板生成文件
    Eclipse中最常用的热键
    struts2的struts.properties配置文件详解 (转)
    eclipse rcp 多线程
    eclipse RPC加载Spring 容器
    使用Apache+tomcat比单独使用tomcat能带来什么样的好处及坏处
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9652145.html
Copyright © 2011-2022 走看看