可爱的模板们

emmm,快比赛了,也是时候把学过的,打过的板子都拿出来晒一晒了。

顺序大部分由luogu提供,不一定按难度排序。码风是与现在最接近的一版(以前的我真毒瘤)

以代码核心为重,不一定能通过luogu的模板题

一、堆

查询/删除最小值,插入一个值,用STL之priority_queue实现

#include<bits/stdc++.h>
using namespace std; 
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        if(x==1) {scanf("%d",&x);q.push(x);}
        else if(x==2) printf("%d
",q.top());
        else q.pop();       
    }
    return 0;
} 
View Code

二、快速排序

对数组进行排序,依旧由STL完成,sort

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
int n,a[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    scanf("%d",&a[i]);
    sort(a,a+n);
    for(int i=0;i<n;i++)
    printf("%d ",a[i]);
    return 0;
}
View Code

三、快速幂

求一个数的n次方(带模数)

#include<bits/stdc++.h>
using namespace std;
long long b,p,k;
long long ksm(long long x,long long y)
{
    int res=1;
    while(y)
    {
        if(y&1)
        res=(res*x)%k;
        x=(x*x)%k;
        y>>=1;
    }
    return res%k;
}
int main()
{
    scanf("%lld%lld%lld",&b,&p,&k);
    printf("%lld",ksm(b,p)%k);
    return 0;
}
View Code

四、线性筛素数

O(n)筛素数

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;


int prime[maxn];
int not_prime[maxn];
int cnt;
int n;
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        if(not_prime[i]==0)
        prime[++cnt]=i;
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>=n)
            break;
            not_prime[i*prime[j]]=1;
            if(i%prime[j]==0)//Èç¹ûÒ»¸öÊý±»Ç°Ãæij¸öÖÊÊýɸµôÁË 
            break;
        }
    }
    for(int i=1;i<=cnt;i++)
    printf("%d ",prime[i]);
    return 0;
}
View Code

 

五、并查集(路径压缩)

维护集合

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m;
int f[maxn];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    f[i]=i;
    while(m--)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==2)
        {
            int fa=find(y);
            int fb=find(z);
            if(fa==fb)
            printf("Y
");
            else
            printf("N
");
        }
        if(x==1)
        {
            int fa=find(y);
            int fb=find(z);
            f[fb]=fa;
        }
    }
    return 0;
}
View Code

六、hash

字符串判重

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int base=131;
int a[maxn];
char s[maxn];
int n,ans=1;
int prime=233317; 
int mod=212370440130137957ll;
int  hash(char s[])
{
    int len=strlen(s);
    int  ans=0;
    for (int i=0;i<len;i++)
    ans=(ans*base+int(s[i]))%mod+prime;
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        a[i]=hash(s);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<n;i++)
    {
        if(a[i]!=a[i+1])
        ans++;
    }
    printf("%d",ans);
    return 0;
} 
View Code

七、最小生成树

#include<bits/stdc++.h>
using namespace std;
const int maxn=5000005;
int m,n,prt[maxn],ans=0,bj;
struct edge
{int x,y,z;}a[maxn];
bool cmp(edge x,edge y){return x.z<y.z;}
int find(int x)
{ return prt[x]==x?x:prt[x]=find(prt[x]);}
void kruskal()
{
    int k=0;
    for(int i=1;i<=n;i++)prt[i]=i;
    for(int i=1;i<m;i++)
    {
        int fa=find(a[i].x);
        int fb=find(a[i].y);
        if(fa!=fb)
        {
            ans+=a[i].z;
            prt[fa]=fb;
            k++;
            //if(k==n-1)
            //break;
        }
    }
        if(k<n-1){cout<<"Orz"<<endl;bj=0;return;}
}
int main()
{
    cin>>n>>m;
    ans=0;bj=1;
    for(int i=1;i<=m;i++)
    cin>>a[i].x>>a[i].y>>a[i].z;
    sort(a+1,a+m+1,cmp);
    kruskal();
    if(bj) cout<<ans<<endl;
    return 0;
}
View Code

八、单源最短路(spfa无优化)

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
const int maxm=5000005;
const int inf=2147483647;
int n,m,s,cnt=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
    int next,to,dis;
}e[maxn];
void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
queue < int > q;
void spfa()
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
        vis[i]=0;
    }
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
        int f,g,w;
        cin>>f>>g>>w;
        addedge(f,g,w);
    }
    spfa();
    for(int i=1;i<=n;i++)
    if(s==i) cout<<'0'<<' ';
    else cout<<dis[i]<<' ';
    return 0;
}
View Code

八点五、单源最短路(流氓优化spfa)

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=500005;
int n,m,head[maxn],cnt,dis[maxn],vis[maxn];
struct edge{int to,next,dis;}e[maxn];
inline void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
struct cmp
{
    bool operator ()(int a,int b)
    {
        return dis[a]>dis[b];
    }
};
priority_queue <int,vector<int>,cmp> q;
void spfa(int s)
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=0x7fffffff;
        vis[i]=0;
    }
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.top();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    int s;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
    }
    spfa(s);
    for(int i=1;i<=n;i++)
    printf("%d ",dis[i]);
    return 0;
}
View Code

八点七五、单源最短路(翟哥版dij)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+10;
ll n,m,s;
struct edge
{
    ll to,next,dis;

}e[maxn];
ll cnt,head[maxn];
inline void addedge(ll from,ll to,ll dis)

{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
struct node
{
    ll x;
    ll v;
    bool operator <(const node &an)const
    {
        return v>an.v;
    }
};
ll dis[maxn];

bitset < maxn > vis,fl;
priority_queue < node > q;
ll dijkstra(int s)
{
    vis.reset();
    memset(dis,0x3f,sizeof(dis));
    q.push((node){s,0});
    dis[s]=0;
    while(!q.empty())
    {
        node s1=q.top();
        q.pop();
        ll u=s1.x;
        if(vis[u]==0)
        {
            vis[u]=1;
            for(ll i=head[u];i;i=e[i].next)
            {
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].dis)
                {
                    dis[v]=dis[u]+e[i].dis;
                    q.push((node){v,dis[v]});

                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
    }
    dijkstra(s);
    for(int i=1;i<=n;i++)
    printf("%d ",dis[i]);
    return 0;
}
View Code

九、树状数组1(单点修改区间查询)

#include<bits/stdc++.h>
using namespace std;
const int maxn=500001;
int m,n,a[maxn];
int lowbit(int k)
{return k & -k;}
int add(int x,int k)
{
    while(x<=n)
    {
        a[x]+=k;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans=0;
    while(x!=0)
    {
        ans+=a[x];
        x-=lowbit(x);
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {scanf("%d",&t);
    add(i,t);}
    for(int i=1;i<=m;i++)
    {
        int q,x,k;
        scanf("%d%d%d",&q,&x,&k);
        if(q==1)
        add(x,k);
        if(q==2)
        cout<<sum(k)-sum(x-1)<<endl;
        //printf("%d
",sum(x)-sum(k-1));
    }
    return 0;
}
View Code

九点五、树状数组2(区间改去检查)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=500001;

ll int m,n,a[maxn],c[maxn];

int lowbit(int k)
{return k & (-k);}

void add(int x,int k)
{
    while(x<=n)
    {
        c[x]+=k;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans=0;
    for(;x;x-=lowbit(x))
        ans+=c[x];
    return ans;
}
int main()
{
    int t;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%ld",&a[i]);add(i,a[i]-a[i-1]);
    }
    while(m--)
    {
        int q;
        scanf("%d",&q);
        if(q==1)
        {
            ll int a,b,c;
            scanf("%lld%lld%lld",&a,&b,&c);
            add(a,c);
            add(b+1,-c);
        }
        if(q==2)
        {
            int x;
            scanf("%d",&x);
            printf("%d
",sum(x));
        }
    }
    return 0;
}
View Code

十、ST表(静态区间最大值)

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100005;
int n,m,a[maxn],dp[maxn][25],l[maxn];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    l[0]=-1;
    for(int i=1;i<=n;++i)
    {
        dp[i][0]=a[i];
        l[i]=l[i>>1]+1;
    }
    for(int j=1;j<=25;++j)
    {
        for(int i=1;i+(1<<j)-1<=n;++i)
        {
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int s=l[y-x+1];
        printf("%d
",max(dp[x][s],dp[y-(1<<s)+1][s]));
    }
    return 0;
}
View Code

十一、KMP(单模式串匹配)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int len, kmp[maxn];
char T[maxn],ch[maxn];
void prework()
{
    int j=-1;kmp[0]=-1;
    for (int i=1;i<len;++i)
    {
         while (j!=-1&&ch[i]!=ch[j+1])
             j=kmp[j];
         if(ch[i]==ch[j+1])
             kmp[i]=++j;
         else kmp[i]=j;
    }
}

int main()
{
    scanf("%s",T);
    scanf("%s",ch);
    len=strlen(ch);
    int lenT=strlen(T);
    prework();
    int j=-1;
    for (int i=0;i<lenT;++i)
    {
        while (j!=-1 &&T[i]!=ch[j+1])
            j=kmp[j];
        if (T[i]==ch[j+1])++j;
        if (j==len-1) 
        {
            cout<<i-j+1<<endl;
            j=kmp[j];
        }
    }
    for(int i=0;i<len;++i)
        cout<<kmp[i]+1<<" ";
    cout<<endl;
    return 0;
}
View Code

十二、线性求逆元

#include<bits/stdc++.h>
const int maxn=3000010;
typedef long long ll;
using namespace std;
int inv[maxn],n,p;
int main()
{
    scanf("%d%d",&n,&p);
    inv[1]=1;puts("1");
    for(int i=2;i<=n;i++)
    { 
        inv[i]=(ll)(p-p/i)*inv[p%i]%p;
        printf("%d
",inv[i]);
    }
}
View Code

十二点五、费马小定理求逆元(要求p一定是质数)

#include<bits/stdc++.h>
using namespace std;
int n,p;
int ksm(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
        res=(res*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return res%p;
}
int main()
{
    scanf("%d%d",&n,&p);
    printf("1
");
    for(int i=2;i<=n;i++)
    {
        printf("%d
",ksm(i,p-2));
    }
    return 0;
}
View Code

十二点七五、exgcd求逆元(要求ab互质,ax+by=1(p为模数))

#include<bits/stdc++.h>
using namespace std;
int n,p,x,y;
int exgcd(int a,int b)
{
    if(!b)
    {
        x=1,y=0;
        return 1;
    }
    int tmp=exgcd(b,a%b);
    int t=x;
    x=y;
    y=t-a/b*y;
    return x;
}
int main()
{
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)
    printf("%d
",(exgcd(i,p)+p)%p);
    return 0;
}
View Code

十三、线段树(区间加)

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct tree
{
    int l,r;
    long long pre,add;
}t[4*maxn+2];
int a[maxn],n;
void build(int p,int l,int r)
{
    t[p].l=l;t[p].r=r;
    if(l==r)
    {
        t[p].pre=a[l];
        return;
    }
    int mid=l+r>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p].pre=t[p<<1].pre+t[p<<1|1].pre;
} 
void spread(int p)
{
    if(t[p].add)
    {
        t[p<<1].pre+=t[p].add*(t[p<<1].r-t[p<<1].l+1);
        t[p<<1|1].pre+=t[p].add*(t[p<<1|1].r-t[p<<1|1].l+1);
        t[p<<1].add+=t[p].add;
        t[p<<1|1].add+=t[p].add;
        t[p].add=0;
    }
}
/*5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4*/
void change(int p,int x,int y,int z)
{
    if(x<=t[p].l&&y>=t[p].r)
    {
        t[p].pre+=(long long)z*(t[p].r-t[p].l+1);
        t[p].add+=z;
        return;
    }
    spread(p);
    int mid=(t[p].l+t[p].r)>>1;
    if(x<=mid)change(p<<1,x,y,z);
    if(y>mid)change(p<<1|1,x,y,z);
    t[p].pre=t[p<<1].pre+t[p<<1|1].pre;
}
long long int ask(int p,int x,int y)
{
    if(x<=t[p].l&&y>=t[p].r)
    return t[p].pre;
    spread(p);
    long long int ans=0;
    int mid=(t[p].l+t[p].r)>>1;
    if(x<=mid)ans+=ask(p<<1,x,y);
    if(y>mid)ans+=ask(p<<1|1,x,y);
    return ans;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int q,x,y,z;
        scanf("%d",&q);
        if(q==1){
            scanf("%d%d%d",&x,&y,&z);
            change(1,x,y,z);
        }
        else {
            scanf("%d%d",&x,&y);
            printf("%lld
",ask(1,x,y));
        }
    }
    return 0;
}
View Code

十三点五、线段树(区间乘)

#include<bits/stdc++.h>
#define lc(x) x<<1
#define rc(x) x<<1|1
using namespace std;
#define ll long long
const int maxn=200005;
int n,m,mod;
ll a[maxn];
struct tree
{
    ll l,r,add,mul,pre;
}t[maxn<<2];
void build(int p,int l,int r)
{
    t[p].mul=1;
    t[p].add=0;
    t[p].l=l;
    t[p].r=r;
    if(l==r)
    {
        t[p].pre=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lc(p),l,mid);
    build(lc(p),mid+1,r);
    t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
void spread(int p)
{
    t[lc(p)].pre=(t[lc(p)].pre*t[p].mul+t[p].add*(t[lc(p)].r-t[lc(p)].l+1))%mod;
    t[lc(p)].pre=(t[lc(p)].pre*t[p].mul+t[p].add*(t[lc(p)].r-t[lc(p)].l+1))%mod;
    t[lc(p)].add=(t[p].add+t[lc(p)].add*t[p].mul)%mod;
    t[lc(p)].add=(t[p].add+t[lc(p)].add*t[p].mul)%mod;
    t[lc(p)].mul=(t[lc(p)].mul*t[p].mul)%mod;
    t[lc(p)].mul=(t[lc(p)].mul*t[p].mul)%mod;
    t[p].add=0;
    t[p].mul=1;
}
void change1(ll p,ll l,ll r,ll z)
{
    spread(p);
    if(t[p].l>=l&&t[p].r<=r)
    {
        t[p].add=(t[p].add+z)%mod;
        t[p].pre=(t[p].pre+z*(t[p].r-t[p].l+1))%mod;
        return;
    }
    ll mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)change1(lc(p),l,r,z);
    if(r>mid) change1(lc(p),l,r,z);
    t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
void change2(int p,int l,int r,int z)
{
    spread(p);
    if(t[p].l>=l&&t[p].r<=r)
    {
        t[p].add=(t[p].add*z)%mod;
        t[p].mul=(t[p].mul*z)%mod;
        t[p].pre=(t[p].mul*t[p].pre)%mod;
        return;
    }
    ll mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)change2(lc(p),l,r,z);
    if(r>mid )change2(lc(p),l,r,z);
    t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
ll ask(int p,int l,int r)
{
    spread(p);
    if(l<=t[p].l&&r>=t[p].r)
    {
        return t[p].pre%mod;
    }
    ll ans=0;
    ll mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)ans+=ask(lc(p),l,r);
    if(r>mid) ans+=ask(lc(p),l,r);
    return ans%mod;
}
int main()
{
    scanf("%d%d%d",&n,&m,&mod);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int flag,l,r;
        scanf("%d%d%d",&flag,&l,&r);
        if(flag==1)
        {
            int k;
            scanf("%d",&k);
            change2(1,l,r,k);
        }
        if(flag==2)
        {
            int k;
            scanf("%d",&k);
            change1(1,l,r,k);
        }
        if(flag==3)
        {
            printf("%lld
",ask(1,l,r));
        }
    }
    return 0;
}
View Code

十四、矩阵加速数列计算

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
ll frog=1000000007;
struct node
{
    ll map[4][4];
}e,ans;
ll t,temp,answer=0;
node mul(node a,node b)
{
    node tp;
    memset(tp.map,0,sizeof(tp));
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
    for(int z=1;z<=3;z++)
    tp.map[i][j]=(tp.map[i][j]+a.map[i][z]*b.map[z][j]%frog)%frog;
    return tp;
}
void quick (node a,ll b)
{
    memset(ans.map,0,sizeof(ans));
    ans.map[1][1]=ans.map[2][2]=ans.map[3][3]=1;
    while(b)
    {
        if(b&1)
        ans=mul(ans,a);
        a=mul(a,a);
        b=(b>>1);
       }
}
int main()
{
    memset(e.map,0,sizeof(e));
    e.map[1][1]=e.map[1][2]=e.map[2][3]=e.map[3][1]=1;
    scanf("%lld",&t);
    for(int i=1;i<=t;i++)
    {
        scanf("%lld",&temp);
        if(temp==1||temp==2||temp==3)
        {
            printf("%d
",1);
            continue;
        }
        quick(e,temp-3);
        printf("%lld
",(ans.map[1][1]+ans.map[2][1]+ans.map[3][1])%frog);
    }
    return 0;
}
View Code

十五、康托展开

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=1e6+10;
const ll mod=998244353;
ll fac[maxn];
ll a[maxn];
ll n;
ll s;
ll t[maxn<<1];
inline ll lowbit(ll x)
{
    return x & - x ;
}
void add(ll x)
{
    while(x<=n)
    {
        t[x]++;
        x+=lowbit(x);
    }
}
ll ask(ll x)
{
    ll res=0;
    while(x)
    {
        res+=t[x];
        x-=lowbit(x);
    }
    return res;
}


int main()
{
    scanf("%lld",&n);

    fac[0]=fac[1]=1;
    for(ll i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);

    }
    for(ll i=2;i<maxn;i++)
    fac[i]=(long long)(fac[i-1]*i)%mod;
    for(ll i=0;i<n;i++)
    {
        s=(s+(long long)fac[n-1-i]*(a[i]-1-ask(a[i]-1))%mod)%mod;
        add(a[i]);

    }
    printf("%lld",(s+1)%mod);
    return 0;
}
View Code

十六、LCA(倍增)

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,p;
struct edge
{
    int next,to;
}e[maxn<<1];
int head[maxn<<1],cnt;
inline void addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
int dep[maxn];
int f[25][maxn];
void dfs(int u,int deep)
{
    int i,v;
    dep[u]=deep;
    for (i=head[u];i;i=e[i].next)
    {
        v=e[i].to;
        if (!dep[v]) dfs(v,deep+1);
        f[0][v]=u;
    }
}
int lca(int a,int b)
{
    if(dep[a]<dep[b])
    swap(a,b);
    for(int i=20;i>=0;i--)
    {
        if(dep[b]<=dep[a]-(1<<i))
        a=f[i][a];
    }
    if(a==b)
    return a;
    for(int i=20;i>=0;i--)
    {
        if(f[i][a]!=f[i][b])
        {
            a=f[i][a];
            b=f[i][b];
        }
    }
    return f[0][a];
}
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    f[0][p]=p;
    dfs(p,1);
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[i][j]=f[i-1][f[i-1][j]];
        }
    }
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d
",lca(a,b));
    }
    return 0;
}
View Code

十六点五、LCA(tarjan)

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,p;
struct edge
{
    int next,to,lca;
}e[maxn<<1],e1[maxn<<1];
int head[maxn<<1],cnt,head1[maxn<<1];
inline int addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
inline int add(int from,int to)
{
    e1[++cnt].next=head1[from];
    e1[cnt].to=to;
    head1[from]=cnt;
}
int f[maxn<<1],vis[maxn<<1];
int find(int x)
{
    if(f[x]!=x)
    f[x]=find(f[x]);
    return f[x];
}
int tarjan(int u)
{
    f[u]=u;
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            tarjan(v);
            f[v]=u;
        }
    }
    for(int i=head1[u];i;i=e1[i].next)
    {
        int v=e1[i].to;
        if(vis[v])
        {
            e1[i].lca=find(v);
            if(i%2==1)
            e1[i+1].lca=e1[i].lca;
            else
            e1[i-1].lca=e1[i].lca;
        }
    }
}


int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    for(int i=1;i<=n;i++)
    f[i]=i;
    cnt=0;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    tarjan(p);
    for(int i=1;i<=m;i++)
    {
        printf("%d
",e1[i*2].lca);
    }
    return 0;
}
View Code

十六点七五、LCA(树剖)

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int n,m,rt;
struct edge
{
    int to, next;
}e[maxn];
int head[maxn], cnt;
inline void addedge(int from,int to)
{
    e[++cnt] = (edge){to, head[from]};
    head[from] = cnt;
}
int son[maxn];
int dfsn[maxn];
int top[maxn];
int dep[maxn];
int fa[maxn];
int w[maxn];
int size[maxn];
void dfs1(int u,int f)
{
    dep[u] = dep[f] + 1;
    size[u] = 1;
    fa[u] = f;
    for (int i = head[u]; i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f)
        continue;
        dfs1(v, u);
        size[u] += size[v];
        if(size[son[u]]<size[v]||son[u]==0)
            son[u] = v;
    }
}
int tot;
void dfs2(int u,int d)
{
    top[u]=d;
    dfsn[u]=++tot;
    if(son[u]!=0)
    dfs2(son[u],d);
    for (int i = head[u]; i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==son[u]||v==fa[u])
        continue;
        dfs2(v, v);
    }
}//以上同树剖,基本没有任何改变
int lca(int x,int y)
{
    while(top[x]!=top[y])//跳到一条链
    {
        if(dep[top[x]]>dep[top[y]])
            swap(x, y);
        y = fa[top[y]];//深度大的向上跳
    }
    return dep[x] < dep[y] ? x : y;//返回深度最浅的点
}
int main()
{
    scanf("%d%d%d", &n, &m, &rt);
    for (int i = 1;i<n;i++)
    {
        int x,y;
        scanf("%d%d", &x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    dfs1(rt, 0);
    dfs2(rt, rt);
    for (int i = 1;i<=m;i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        printf("%d
", lca(x, y));
    }
    return 0;
}
View Code

 

十七、最长公共子序列

#include<bits/stdc++>h>
using namespace std;
const int maxn=100001;
int m,list[maxn],a,ans[maxn],n;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>m;
        list[m]=i;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>m;
        int la=list[m];
        if(la>ans[a])ans[++a]=la;
        else
        {
            int l=0,r=a;
            while(l<=r)
            {
                int mid=ans[(l+r)/2];
                if(la<mid)r=(l+r)/2-1;
                else l=(l+r)/2+1;
            }
            ans[l]=la;
        }
    }
    printf("%d",a);
    return 0;
}
View Code

十八、nim游戏

#include<bits/stdc++.h>
using namespace std;
int n,ans;
int T;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            ans^=x;
        }
        if(ans==0)
        printf("No
");
        else printf("Yes
");
        ans=0;
    }
    return 0;
}
View Code

十九、Lucas定理(求C(n,m+n))

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
long long n,m,p;
long long ksm(long long a,long long b)
{
    a%=p;
    long long res=1;
    while(b)
    {
        if(b%2==1)
        res=(res*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return res;
}
long long fac[maxn];
long long C(long long a,long long b)
{
    if(a<b)
    return 0;
    return (fac[a]*ksm(fac[b],p-2))%p*ksm(fac[a-b],p-2)%p;
}

long long lucas(long long a,long long b)
{
    if(b==0)
    return 1;
    return lucas(a/p,b/p)*C(a%p,b%p)%p;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        fac[0]=1;
        for(long long i=1;i<=p;i++)
        {
            fac[i]=(fac[i-1]*i)%p;
        }
        printf("%lld
",lucas(n+m,n));
    }
    return 0;
}
View Code

二十、二分图最大匹配(匈牙利)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=1000005;
int cnt,n,m,q,ans,head[maxn<<1];
int vis[maxn],match[maxn];
struct edge
{
    int to,next;
}e[maxm];
inline void addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
bool dfs(int u)
{
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            vis[v]=1;
            if(!match[v]||dfs(match[v]))
            {
                match[v]=u;
                return 1;
            }
        } 
    }
    return 0;
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(y<=m)
        addedge(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        ans+=dfs(i);
        memset(vis,0,sizeof(vis));
    }
    printf("%d",ans);
    return 0;
}
View Code

二十一、tarjan求割点

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,head[maxn],cnt,num;
int dfn[maxn],low[maxn],co[maxn],ans;
struct edge{int to,next;}e[maxn];
inline void addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
void tarjan(int u,int fa)
{
    low[u]=dfn[u]=++num;
    int child=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v,fa);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&u!=fa)
            co[u]=1;
            if(u==fa)
            child++;
        }
        low[u]=min(low[u],dfn[v]);
    }
    if(child>=2&&u==fa)
    co[u]=1;
}        

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    tarjan(i,i);
    for(int i=1;i<=m;i++)
    if(co[i]!=0)
    ans++;
    printf("%d
",ans);
    for(int i=1;i<=m;i++)
    if(co[i]!=0)
    printf("%d ",i);
    return 0;
}
View Code

二十二、tarjan缩点

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct node
{
    int next,to;
}e[maxn];
int head[maxn],cnt,sum[maxn],a[maxn];
int n,m,ru[maxn];
inline void addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
int dep,top;
int dfn[maxn],low[maxn],vis[maxn],co[maxn],st[maxn];
void tarjan(int u)
{
    dfn[u]=low[u]=++dep;
    vis[u]=1;
    st[++top]=u;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[v],low[u]);
        }
        else if(vis[v])
        {
            low[u]=min(low[u],low[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        int t;
        do
        {
            t=st[top--];
            sum[u]+=a[t];
            co[t]=u;
            vis[t]=0;
        }while(t!=u);
    }
}
int dp[maxn];

queue < int > q;
void tpsort()
{
    for(int i=1;i<=n;i++)
    {
        if(ru[i]==0&&co[i]==i)
        q.push(i);
        dp[co[i]]=sum[co[i]];
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            dp[v]=max(dp[u]+sum[co[v]],dp[v]);
            if(!(--ru[v]))
            {
                q.push(v);
            }
        }
    }
}
    
pair < int , int > g[maxn];
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++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        g[i].first=x;
        g[i].second=y;
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        tarjan(i);
    }
    memset(e,0,sizeof(e));
    memset(head,0,sizeof(head));
    cnt=0;
    for(int i=1;i<=m;i++)
    {
        int x=g[i].first;
        int y=g[i].second;
        if(co[x]!=co[y])
        {
            addedge(co[x],co[y]);
            ru[co[y]]++;
        }
    }
    tpsort();
    int ans=-1;
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,dp[i]);
    }
    printf("%d",ans);
    return 0;
}
View Code

二十三、负环(spfa)

#include<bits/stdc++.h>
using namespace std;
const int maxn=6010;
int t,m,n;
struct edge
{
    int dis,to,next;
}e[maxn<<1];
int head[maxn],cnt;
inline void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].dis=dis;
    e[cnt].to=to;
    head[from]=cnt;
}
int dis[maxn],vis[maxn],dfn[maxn];
queue < int > q;
int spfa(int s)
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=0x7fffffff;
        vis[i]=0;
        dfn[i]=0;
    }
    //dfn[s]=1;
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        if(dfn[u]>n)
        return 1;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                if(vis[v]==0)
                {
                    dfn[v]++;
                    q.push(v);
                    vis[v]=1;
                    if(dfn[v]>=n)
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            if(z<0)
            addedge(x,y,z);
            else addedge(x,y,z),addedge(y,x,z);
        }
        if(spfa(1)==1)
        printf("YE5
");
        else printf("N0
");
        memset(head,0,sizeof(head));
        cnt=0;
        while(!q.empty())q.pop();
    }
    return 0;
}
View Code

二十四、最大流(dinic)

#include<bits/stdc++.h>
using namespace std;
const int maxn=500010;
int n,m,s,t;
int cnt,head[maxn],vis[maxn];
int dep[maxn];
struct edge
{
    int to,next,dis;
}e[maxn];
inline int addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
queue < int > q;
bool spfa()
{
    memset(dep,0x3f,sizeof(dep));
    memset(vis,0,sizeof(vis));
    dep[s]=1;
    vis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(e[i].dis&&dep[u]+1<dep[v])
            {
                dep[v]=dep[u]+1;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dep[t]!=0x3f3f3f3f)
    return 1;
    else return 0;
}
int dfs(int u,int flow)
{
    int rlow=0;
    if(u==t)return flow;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(e[i].dis&&dep[v]==dep[u]+1)
        {
            if(rlow=dfs(v,min(flow,e[i].dis)))
            {
                e[i].dis-=rlow;
                e[i+1].dis+=rlow;
                return rlow;
            }
        }
    }
    return 0;
}
int dinic()
{
    int maxflow=0;
    int lowflow;
    while(spfa())
    {
        while(lowflow=dfs(s,0x7fffffff))
        maxflow+=lowflow;
    }
    return maxflow;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
        addedge(v,u,0);
    }
    printf("%d",dinic());
    return 0;
}
View Code

二十四点五、最大流(EK)

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int n,m,s,t,head[maxn],cnt=1,vis[maxn];
struct edge
{
    int next,dis,to;
}e[maxn];
inline void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].dis=dis;
    e[cnt].to=to;
    head[from]=cnt;
}
struct edge1
{
    int v,edge;
}pre[maxn];
bool bfs()
{
    queue < int > q;
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    vis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(!vis[v]&&e[i].dis)
            {
                pre[v].v=u;
                pre[v].edge=i;
                if(v==t)
                return 1;
                vis[v]=1;
                q.push(v);
            }
        }
    }
    return 0;
}
int ek()
{
    int ans=0;
    while(bfs())
    {
        int mi=0x7fffffff;
        for(int i=t;i!=s;i=pre[i].v)
        {
            mi=min(mi,e[pre[i].edge].dis);
        }
        for(int i=t;i!=s;i=pre[i].v)
        {
            e[pre[i].edge].dis-=mi;
            e[pre[i].edge^1].dis+=mi;
        }
        ans+=mi;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
        addedge(y,x,0);
    }
    printf("%d",ek());
}
View Code

二十五、最小费用最大流

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=200010;
int cost=0,n,m,s,t,head[maxn],cnt=1,vis[maxn],dis[maxn];
inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct edge
{
    int next,dis,to,w;
}e[maxn];
inline void addedge(int from,int to,int dis,int w)
{
    e[++cnt].next=head[from];
    e[cnt].dis=dis;
    e[cnt].to=to;
    e[cnt].w=w;
    head[from]=cnt;
}
struct edge1
{
    int v,edge;
}pre[maxn];
struct cmp
{
    bool operator () (int a,int b)
    {
        return dis[a]>dis[b];
    }
};
priority_queue < int , vector < int > , cmp > q;

bool spfa()
{
    memset(pre,0,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.top();
        q.pop();
        vis[u]=0;
        for(register int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(dis[v]>dis[u]+w&&e[i].dis>0)
            {
                dis[v]=dis[u]+w;
                pre[v].v=u;
                pre[v].edge=i;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return dis[t]!=0x3f3f3f3f;
}
int ek()
{
    int ans=0;
    cost=0;
    while(spfa())
    {
        int mi=0x7fffffff;
        for(register int i=t;i!=s;i=pre[i].v)
        {
            mi=min(mi,e[pre[i].edge].dis);
        }
        for(register int i=t;i!=s;i=pre[i].v)
        {
            e[pre[i].edge].dis-=mi;
            e[pre[i].edge^1].dis+=mi;
        }
        ans+=mi;
        cost+=mi*dis[t];
    }
    return ans;
}
int main()
{
    n=read();m=read();s=read();t=read();//scanf("%d%d%d%d",&n,&m,&s,&t);
    for(register int i=1;i<=m;i++)
    {
        int x,y,z,w;
        x=read();y=read();z=read();w=read();//scanf("%d%d%d%d",&x,&y,&z,&w);
        addedge(x,y,z,w);
        addedge(y,x,0,-w);
    }
    printf("%d",ek());
    printf(" %d",cost);
    return 0;
}
View Code

二十六、主席树(静态区间第k大)

#include<bits/stdc++.h>
using namespace std;
const int maxn=5000005;
int n,m,a[maxn],b[maxn];
int sum[maxn];
int rt[maxn];
int cnt,len;
int ls[maxn],rs[maxn];
int build(int l,int r)
{
    int root=++cnt;
    if(l==r)return root;
    int mid=l+r>>1;
    ls[root]=build(l,mid);
    rs[root]=build(mid+1,r);
    return root;
}

int update(int l,int r,int root,int k)
{
    int newroot=++cnt;
    ls[newroot]=ls[root];
    rs[newroot]=rs[root];
    sum[newroot]=sum[root]+1;
    if(l==r)return newroot;
    int mid=l+r>>1;
    if(k<=mid)ls[newroot]=update(l,mid,ls[newroot],k);
    else rs[newroot]=update(mid+1,r,rs[newroot],k);
    return newroot;
}

int query(int ll,int rr,int l,int r,int k)
{
    int mid=l+r>>1;
    int w=sum[ls[rr]]-sum[ls[ll]];
    if(l==r)return l;
    else if(k<=w) return query(ls[ll],ls[rr],l,mid,k);
    else return query(rs[ll],rs[rr],mid+1,r,k-w);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    len=unique(b+1,b+n+1)-b-1; 
    rt[0]=build(1,len);
    for(int i=1;i<=n;i++)´Î¼Ó±ß 
    {
        int x=lower_bound(b+1,b+1+len,a[i])-b; 
        rt[i]=update(1,len,rt[i-1],x);//иùµÄ±àºÅ 
    
    }
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        printf("%d
",b[query(rt[x-1],rt[y],1,len,z)]);
    }
    return 0;
}
View Code

二十六点五、主席树(历史版本)

#include<bits/stdc++.h>
using namespace std;
const int maxn=20000001;
int n,m,cnt;
int a[maxn];
int dis[maxn];
int rs[maxn];
int ls[maxn];
int rt[maxn];
int build(int l,int r)
{
    int root=++cnt;
    if(l==r)
    {
        dis[root]=a[l];//Ïñ¼«ÁËÏ߶ÎÊ÷233 
        return root;
    }
    int mid=l+r>>1;
    ls[root]=build(l,mid);
    rs[root]=build(mid+1,r);
    return root;
}
int updata(int l,int r,int root,int x,int k)
{
    int newroot=++cnt;
    if(l==r)
    {
        dis[newroot]=x;
        return newroot;
    }
    ls[newroot]=ls[root];
    rs[newroot]=rs[root];
    int mid=l+r>>1;
    if(k<=mid)ls[newroot]=updata(l,mid,ls[newroot],x,k);
    else rs[newroot]=updata(mid+1,r,rs[newroot],x,k);
    return newroot;
}
void query(int l,int r,int root,int x)
{
    if(l==r)
    {
        printf("%d
",dis[root]);
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid)query(l,mid,ls[root],x);
    else query(mid+1,r,rs[root],x);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    rt[0]=build(1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(y==1)
        {
            int flag;
            scanf("%d",&flag);
            rt[i]=updata(1,n,rt[x],flag,z);
        }
        if(y==2)
        {
            rt[i]=rt[x];
            query(1,n,rt[x],z);
        }
    }
    return 0;
}
View Code

二十七、普通平衡树(treap实现)

  1. 插入xx数
  2. 删除xx数(若有多个相同的数,因只删除一个)
  3. 查询xx数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为xx的数
  5. xx的前驱(前驱定义为小于xx,且最大的数)
  6. xx的后继(后继定义为大于xx,且最小的数)
#include<cstdio>
#include<iostream>
#include<climits>
#include<algorithm>
using namespace std;
const int maxn=2e6+10;
const int inf=0x7fffffff;
int n,rt,tot;
struct node
{
    int lc,rc,key,pri,cnt,size;
    #define lc(x) t[x].lc
    #define rc(x) t[x].rc
    #define v(x) t[x].key
    #define p(x) t[x].pri
    #define c(x) t[x].cnt
    #define s(x) t[x].size
}t[maxn];
inline void upt( int &k)
{
    s(k)=s(lc(k))+s(rc(k))+c(k);
}
inline void tr(int &k)//right
{
    int y=rc(k);
    rc(k)=lc(y);
    lc(y)=k;
    s(y)=s(k);
    upt(k);
    k=y;
}
inline void tl(int &k)//left
{
    int y=lc(k);
    lc(k)=rc(y);
    rc(y)=k;
    s(y)=s(k);
    upt(k);
    k=y;
}
inline void insert(int &k, int key)
{
    if(!k)
    {
        k=++tot;
        v(k)=key;
        p(k)=rand();
        c(k)=s(k)=1;
        lc(k)=rc(k)=0;
        return;
    }
    else ++s(k);
    if(v(k)==key)
    ++c(k);
    else if(key<v(k))
    {
        insert(lc(k),key);
        if(p(lc(k))<p(k))
        tl(k);
    }
    else
    {
        insert(rc(k),key);
        if(p(rc(k))<p(k))
        tr(k);
    }
    return;
}
inline void Delete(int &k, int key)
{
    if(v(k)==key)
    {
        if(c(k)>1)
        {
            --c(k);
            --s(k);
        }
        else if(!lc(k)||!rc(k))
        {
            k=lc(k)+rc(k);
        }
        else if(p(lc(k))<p(rc(k)))
        {
            tl(k);
            Delete(k,key);
        }
        else
        {
            tr(k);
            Delete(k,key);
        }
        return ;
    }
    --s(k);
    if(key<v(k))
    Delete(lc(k),key);
    else
    Delete(rc(k),key);
    return;
}
inline int getpre( int key)
{
    int x=rt;
    int res=-inf;
    while(x)
    {
        if(v(x)<key)
        res=v(x),x=rc(x);
        else x=lc(x);
    }
    return res;
}
inline int getsuf( int key)
{
    int x=rt;
    int res=inf;
    while(x)
    {
        if(v(x)>key)
        res=v(x),x=lc(x);
        else x=rc(x);
    }
    return res;
}
inline int kth(int k)
{
    int x=rt;
    while(x)
    {
        if(s(lc(x))<k)
        {
            if(s(lc(x))+c(x)>=k)
            return v(x);
            else
            k=k-s(lc(x))-c(x),x=rc(x);
        }
        else
        x=lc(x);
    }
}
inline int Rank( int key)
{
    int x=rt;
    int res=0;
    while(x)
    {
        if(key==v(x))
        return res+s(lc(x))+1;
        if(key<v(x))
        x=lc(x);
        else
        res+=s(lc(x))+c(x),x=rc(x);
    }
    return res;
}
int main()
{
    scanf("%d",&n);
    s(1)=1;v(1)=2147483647;c(1)=1;p(1)=rand();
    while(n--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x==1)insert(rt,y);
        if(x==2)Delete(rt,y);
        if(x==3)printf("%d
",Rank(y));
        if(x==4)printf("%d
",kth(y));
        if(x==5)printf("%d
",getpre(y));
        if(x==6)printf("%d
",getsuf(y));
    }
    return 0;
}
View Code

fhqtreap实现:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
struct tree
{
    int son[2], v, key, size;
} t[maxn];
int tot = 0, rt = 0;
void update(int p)
{
    t[p].size = t[t[p].son[0]].size + t[t[p].son[1]].size + 1;
}
int new_node(int k)//暴力建新节点
{
    tot++;
    t[tot].size = 1;
    t[tot].v = k;
    t[tot].key = rand();
    return tot;
}
int merge(int x, int y) //将两棵以xy为根的树合并到一起,并返回根节点
{
    if (!x || !y)//动态开点
        return x + y;
    if (t[x].key < t[y].key)//维护堆
    {
        t[x].son[1] = merge(t[x].son[1], y);//打散,合并子树
        update(x);//更新
        return x;//返回根节点
    }
    else//同上
    {
        t[y].son[0] = merge(x, t[y].son[0]);
        update(y);
        return y;
    }
}
void split(int now, int k, int &x, int &y) //将now这棵树在k处断成x,y两棵树
{
    if (!now)
        x = y = 0;
    else
    {
        if (t[now].v <= k) //维护BST
        {
            x = now;
            split(t[now].son[1], k, t[now].son[1], y);//向下拆分
        }
        else
        {
            y = now;
            split(t[now].son[0], k, x, t[now].son[0]);//同上
        }
        update(now);
    }
}
int kth(int now, int k)//跟普通的BST一样遍历
{
    while (1)
    {
        if (k <= t[t[now].son[0]].size)
            now = t[now].son[0];
        else
        {
            if (k == t[t[now].son[0]].size + 1)
                return now;
            else
            {
                k -= t[t[now].son[0]].size + 1;
                now = t[now].son[1];
            }
        }
    }
}
int x, y, z, n;
int main()
{
    srand((unsigned)time(NULL));
    scanf("%d", &n);
    int flag, a, b, c;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &flag);
        scanf("%d", &a);
        if (flag == 1)
        {
            split(rt, a, x, y);//先把树拆散,在a(给定值处)
            rt = merge(merge(x, new_node(a)), y);//然后把新节点看做一棵树,把上面的和新节点并在一起,然后再并下面的
        }
        if (flag == 2)
        {
            split(rt, a, x, z);//在a处断开,分成xz
            split(x, a - 1, x, y);//把x断开,在a-1处,这时的y的根节点一定是要删除的点
            y = merge(t[y].son[0], t[y].son[1]);//然后把y的左右儿子插到一起,消除a的影响
            rt = merge(merge(x, y), z);//合并大树
        }
        if (flag == 3)
        {
            split(rt, a - 1, x, y);//直接断开
            printf("%d
", t[x].size + 1);//rt为根的树的大小即是排名
            rt = merge(x, y);//别忘了合回来
        }
        if (flag == 4)
        {
            printf("%d
", t[kth(rt, a)].v);//直接遍历
        }
        if (flag == 5)
        {
            split(rt, a - 1, x, y);//把整棵树断开,在左树里找第size-1个
            printf("%d
", t[kth(x, t[x].size)].v);
            rt = merge(x, y);//还是要回来
        }
        if (flag == 6)
        {
            split(rt, a, x, y);//同上
            printf("%d
", t[kth(y, 1)].v);
            rt = merge(x, y);
        }
    }
    return 0;
}
View Code

二十八、树链剖分(线段树维护)

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e6+10;
int n,m,r,mod;
int a[maxn];
struct edge
{
    int to,next;
}e[maxn];
int head[maxn],cnt;
inline int addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
int rt=0;
int son[maxn];
int size[maxn];
int top[maxn];
int dep[maxn];
int dfsn[maxn];
int fa[maxn];
int newid[maxn];
int tot;
struct tree
{
    int l,r,ls,rs,pre,add;
}t[maxn];
void dfs1(int u)
{
    size[u]=1;
    dep[u]=dep[fa[u]]+1;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa[u])
        {
            fa[v]=u;
            dfs1(v);
            size[u]+=size[v];
            if(size[son[u]]<size[v])
            son[u]=v;
        }
    }
}
void dfs2(int u,int d)
{
    top[u]=d;
    dfsn[u]=++tot;
    newid[tot]=u;
    if(son[u])
    dfs2(son[u],d);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        dfs2(v,v);
    }
}

inline void pushup(int p)
{
    t[p].pre=(t[t[p].ls].pre+t[t[p].rs].pre)%mod;
}

void build(int l,int r,int p)
{
    if(l==r)
    {
        t[p].pre=a[newid[l]];
        t[p].l=t[p].r=l;
        return ;
    }
    int mid=l+r>>1;
    t[p].ls=tot++;
    t[p].rs=tot++;
    build(l,mid,t[p].ls);
    build(mid+1,r,t[p].rs);
    t[p].l=t[t[p].ls].l;
    t[p].r=t[t[p].rs].r;
    pushup(p);
}
inline int len(int p)
{
    return t[p].r-t[p].l+1;
}
void spread(int p)
{
    if(t[p].add)
    {
        int ls=t[p].ls,rs=t[p].rs,lz=t[p].add;
        t[ls].add=(t[ls].add+lz)%mod;
        t[rs].add=(t[rs].add+lz)%mod;
        t[ls].pre=(t[ls].pre+lz*len(ls))%mod;
        t[rs].pre=(t[rs].pre+lz*len(rs))%mod;
        t[p].add=0;
    }
}
void change(int l,int r,int k,int p)
{
    if(l<=t[p].l&&r>=t[p].r)
    {
        t[p].pre=(t[p].pre+k*(t[p].r-t[p].l+1))%mod;
        t[p].add=(t[p].add+k)%mod;
        return;
    }
    spread(p);
    int mid=t[p].l+t[p].r>>1;
    if(l<=mid)change(l,r,k,t[p].ls);
    if(r>mid) change(l,r,k,t[p].rs);
    pushup(p);
}
int ask(int l,int r,int p)
{
    if(t[p].l>=l&&t[p].r<=r)
        return t[p].pre%mod;
    spread(p);
    int mid=t[p].l+t[p].r>>1,res=0;
    if(mid>=l)res=(res+ask(l,r,t[p].ls))%mod;
    if(mid<r) res=(res+ask(l,r,t[p].rs))%mod;
    return res%mod;
}
inline int sum(int x,int y)
{
    int ret=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
        swap(x,y);
        ret=(ret+ask(dfsn[top[x]],dfsn[x],rt)%mod);
        x=fa[top[x]];
    }
    if(dfsn[x]>dfsn[y])
    swap(x,y);
    return (ret+ask(dfsn[x],dfsn[y],rt))%mod;
}
inline void updates(int x,int y,int c)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
        swap(x,y);
        change(dfsn[top[x]],dfsn[x],c,rt);
        x=fa[top[x]];
    }
    if(dfsn[x]>dfsn[y])
    swap(x,y);
    change(dfsn[x],dfsn[y],c,rt);
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&mod);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs1(r);
    dfs2(r,r);
    tot=0;
    build(1,n,rt=tot++);
    for(int i=1;i<=m;i++)
    {
        int flag,x,y,z;
        scanf("%d",&flag);
        if(flag==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            updates(x,y,z);
        }
        if(flag==2)
        {
            scanf("%d%d",&x,&y);
            printf("%d
",sum(x,y)%mod);
        }
        if(flag==3)
        {
            scanf("%d%d",&x,&z);
            change(dfsn[x],dfsn[x]+size[x]-1,z,rt);
        }
        if(flag==4)
        {
            scanf("%d",&x);
            printf("%d
",ask(dfsn[x],dfsn[x]+size[x]-1,rt)%mod);
        }
    }
    return 0;
}
View Code(动态开点线段树)
#include <bits/stdc++.h>
#define lc(x) x << 1
#define rc(x) x << 1 | 1
using namespace std;
const int maxn = 1e6 + 10;
int n, m, rt, mod;
int a[maxn];
struct edge
{
    int to, next;
} e[maxn];
int head[maxn], cnt;
inline void addedge(int from, int to)
{
    e[++cnt].next = head[from];
    e[cnt].to = to;
    head[from] = cnt;
}
int fa[maxn];   //
int dep[maxn];  //
int son[maxn];  //
int size[maxn]; //
int top[maxn];  //
int w[maxn];    //
int dfsn[maxn]; //
void dfs1(int u, int f)
{
    fa[u] = f;
    dep[u] = dep[f] + 1;
    size[u] = 1;
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == f)
            continue;
        dfs1(v, u);
        size[u] += size[v];
        if (size[son[u]] < size[v] || son[u] == 0)
            son[u] = v;
    }
}
int tot;
void dfs2(int u, int d)
{
    dfsn[u] = ++tot;
    w[tot] = a[u];
    top[u] = d;
    if (son[u] != 0)
        dfs2(son[u], d);
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v, v);
    }
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
struct tree
{
    int l, r, sum, add;
} t[maxn];
void pushup(int p)
{
    t[p].sum = (t[lc(p)].sum + t[rc(p)].sum) % mod;
}
int len(int p)
{
    return t[p].r - t[p].l + 1;
}
void build(int l, int r, int p)
{
    t[p].l = l;
    t[p].r = r;
    if (l == r)
    {
        t[p].sum = w[l];
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, lc(p));
    build(mid + 1, r, rc(p));
    pushup(p);
}
void spread(int p)
{
    if (t[p].add != 0)
    {
        t[lc(p)].add = (t[lc(p)].add + t[p].add) % mod;
        t[rc(p)].add = (t[rc(p)].add + t[p].add) % mod;
        t[lc(p)].sum = (t[lc(p)].sum + t[p].add * len(lc(p))) % mod;
        t[rc(p)].sum = (t[rc(p)].sum + t[p].add * len(rc(p))) % mod;
        t[p].add = 0;
    }
}
void change(int l, int r, int k, int p)
{
    if (l <= t[p].l && t[p].r <= r)
    {
        t[p].add = (t[p].add + k) % mod;
        t[p].sum = (t[p].sum + len(p) * k) % mod;
        return;
    }
    spread(p);
    int mid = t[p].l + t[p].r >> 1;
    if (l <= mid)
        change(l, r, k, lc(p));
    if (r > mid)
        change(l, r, k, rc(p));
    pushup(p);
}
int ask(int l, int r, int p)
{
    if (l <= t[p].l && t[p].r <= r)
    {
        return t[p].sum % mod;
    }
    spread(p);
    int mid = t[p].l + t[p].r >> 1;
    int res = 0;
    if (l <= mid)
        res = (res + ask(l, r, lc(p))) % mod;
    if (r > mid)
        res = (res + ask(l, r, rc(p))) % mod;
    return res % mod;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~*/
void update(int x, int y, int k)
{
    k = k % mod;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        change(dfsn[top[x]], dfsn[x], k, 1);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    change(dfsn[x], dfsn[y], k, 1);
}
int query(int x, int y)
{
    int res = 0;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        res = (res + ask(dfsn[top[x]], dfsn[x], 1)) % mod;
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    res = (res + ask(dfsn[x], dfsn[y], 1)) % mod;
    return res % mod;
}
int main()
{
    scanf("%d%d%d%d", &n, &m, &rt, &mod);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (int i = 1; i < n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    dfs1(rt, 0);
    dfs2(rt, rt);
    build(1, n, 1);
    for (int i = 1; i <= m; i++)
    {
        int f, x, y, z;
        scanf("%d", &f);
        if (f == 1)
        {
            scanf("%d%d%d", &x, &y, &z);
            update(x, y, z);
        }
        if (f == 2)
        {
            scanf("%d%d", &x, &y);
            printf("%d
", query(x, y));
        }
        if (f == 3)
        {
            scanf("%d%d", &x, &z);
            change(dfsn[x], dfsn[x] + size[x] - 1, z, 1);
        }
        if (f == 4)
        {
            scanf("%d", &x);
            printf("%d
", ask(dfsn[x], dfsn[x] + size[x] - 1, 1));
        }
    }
    return 0;
}
View Code(船新版本堆式线段树,船新码风)

二十九、三维偏序(CDQ实现)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node
{
    int nth,a,b,c;
}a[maxn];
int n,k;
int f[maxn],same[maxn],t[maxn<<1],ans[maxn];
inline int lowbit(int x)
{
    return x & - x ;
}
void add(int x,int y)
{
    for(;x<=k;x+=lowbit(x))
    {
        t[x]+=y;
    }
}
int ask(int x)
{
    int res=0;
    for(;x;x-=lowbit(x))
    {
        res+=t[x];
    }
    return res;
}
bool cmp1(node a,node b)
{
    if(a.a!=b.a)return a.a<b.a;
    if(a.b!=b.b)return a.b<b.b;
    else        return a.c<b.c;
}
bool cmp2(node a,node b)
{
    if(a.b!=b.b)return a.b<b.b;
    if(a.c!=b.c)return a.c<b.c;
    else        return a.a<b.a;
}
void cdq(int l,int r)
{
    if(l==r)
    return;
    int mid=l+r>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    sort(a+l,a+1+r,cmp2);
    for(int i=l;i<=r;i++)
    {
        if(a[i].a<=mid)
        {
            add(a[i].c,1);
        }
        else
        {
            ans[a[i].nth]+=ask(a[i].c);
        }
    }
    for(int i=l;i<=r;i++)
    {
        if(a[i].a<=mid)
        add(a[i].c,-1);
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
        a[i].nth=i;
    }
    sort(a+1,a+n+1,cmp1);
    for(int i=1;i<=n;)
    {
        int j=i+1;
        while(j<=n&&a[i].a==a[j].a&&a[i].b==a[j].b&&a[i].c==a[j].c)
        j++;
        while(i<j)
        same[a[i++].nth]=a[j-1].nth;
    }
    for(int i=1;i<=n;i++)
    {
        a[i].a=i;
    }
    cdq(1,n);
    for(int i=1;i<=n;i++)
    f[ans[same[a[i].nth]]]++;
    for(int i=0;i<n;i++)
    printf("%d
",f[i]);
    return 0;
}
View Code

三十、2-SAT

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
int n,m;
struct edge
{
    int to,next;
}e[maxn];
int head[maxn],cnt;
inline void addedge(int from,int to)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
int dfn[maxn],low[maxn],tot;
stack < int > st;
int vis[maxn];
int scccnt;
int co[maxn];
void tarjan(int u)
{
    dfn[u]=low[u]=++tot;
    vis[u]=1;
    st.push(u);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        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])
    {
        ++scccnt;
        do
        {
            co[u]=scccnt;
            u=st.top();
            st.pop();
            vis[u]=0;
        }while(low[u]!=dfn[u]);
    }
}
bool two_sat()
{
    for(int i=1;i<=2*n;i++)
    {
        if(!dfn[i])
        tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
        if(co[i]==co[i+n])
        return 0;
    }
    return 1;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,va,vb;
        scanf("%d%d%d%d",&a,&va,&b,&vb);
        int nota=va^1,notb=vb^1;
        addedge(a+nota*n,b+vb*n);
        addedge(b+notb*n,a+va*n);
    }
    if(two_sat()==1)
    {
        printf("POSSIBLE
");
        for(int i=1;i<=n;i++)
        {
            printf("%d ",co[i]>co[i+n]);
        }
    }
    else
    printf("IMPOSSIBLE");
    return 0;
}
View Code

 三十一、最大公约数(gcd压行和不压行)

int gcd(int a,int b)
{
    if(b==0)
    return a;
    return gcd(b,a%b);
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);};
View Code

三十二、拓展欧几里得定理(exgcd)(求关于x的同余方程 ax1(mod b) 的最小正整数解。

#include<bits/stdc++.h>
using namespace std;
int x,y;
void exgcd(int a,int b)
{
    if(!b)
    {
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a%b);
    int z=x;
    x=y;
    y=z-a/b*y;
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    exgcd(a,b);
    printf("%d",(x+b)%b);
    return 0;
}
View Code

 三十三、最短路之Floyd(动态规划求最短路)(牢记枚举顺序ijk)

for(int k=1;k<=n;k++)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(dis[i][j]>dis[i][k]+dis[k][j])
            {
                dis[i][j]=dis[i][k]+dis[k][j];
            }
        }
    }
}
View Code

三十四、对拍(maker)造数据的

#include<bits/stdc++.h>
using namespace std;
int main()
{
    freopen("data.in","w",stdout);
    srand(time(NULL));
    int n=rand();
    int m=rand();//可以在这里加模数来控制范围 
    cout<<n<<" "<<m<<endl;
}
View Code

三十四点五、对拍(check)跑数据和暴力的

这个在用之前一定要先把所有的程序先跑一下,然后一定要在同一各根目录下,不然有可能会用一些很神奇的东西把源程序给覆盖掉

#include<bits/stdc++.h>
using namespace std;
int main()
{
    while(1)
    {
        system("maker");
        system("true");
        system("false");
        if(system("fc false.out true.out")
        {
            cout<<"WA"<<endl;
            break;
        }
        cout<<"AC"<<endl;
    }
    return 0;
 }
View Code

三十五、tpsort(求一个图的拓扑序)

void tpsort()
{
    queue < int > q;
    for( int i=1;i<n;i++)
    {
        if(ru[i]==0)
        q.push(i);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for( int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            ru[v]--;
            if(ru[v]==0)
            {
                q.push(v);
            }
        }
    }
}
View Code

三十六、高精加减乘除取模开根(封装结构体)(来自2529102757)

#include <bits/stdc++.h>
using namespace std;
struct node
{
    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<long long> s;
    node()
    {
        *this = 0;
    }
    node(const int &num)
    {
        *this = num;
    }

    node operator=(int num)
    {
        s.clear();
        do
        {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    node operator=(const string &str)
    {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; i++)
        {
            int end = str.length() - i * WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start, end - start).c_str(), "%lld", &x);
            s.push_back(x);
        }
        return *this;
    }
    bool operator<(const node &b)
    {
        if (s.size() < b.s.size())
            return true;
        if (s.size() > b.s.size())
            return false;
        for (int i = s.size() - 1; i >= 0; i--)
        {
            if (s[i] < b.s[i])
                return true;
            if (s[i] > b.s[i])
                return false;
        }
        return false;
    }
    bool operator>=(const node &b)
    {
        return !(*this < b);
    }
    bool operator==(const node &b)
    {
        if (s.size() != b.s.size())
            return false;
        for (int i = 0; i < s.size(); i++)
            if (s[i] != b.s[i])
                return false;
        return true;
    }
    node operator+(const node &b)
    {
        node c;
        c.s.clear();
        for (int i = 0, g = 0;; i++)
        {
            if (g == 0 && i >= s.size() && i >= b.s.size())
                break;
            int x = g;
            if (i < s.size())
                x += s[i];
            if (i < b.s.size())
                x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    node operator-(const node &b)
    {
        node c;
        c = *this;
        for (int i = 0; i < c.s.size(); i++)
        {
            int tmp;
            if (i >= b.s.size())
                tmp = 0;
            else
                tmp = b.s[i];
            if (c.s[i] < tmp)
            {
                c.s[i + 1] -= 1;
                c.s[i] += BASE;
            }
            c.s[i] -= tmp;
        }
        while (c.s.back() == 0 && c.s.size() > 1)
            c.s.pop_back();
        return c;
    }
    void operator-=(const node &b)
    {
        *this = *this - b;
    }
    node operator*(const node &b)
    {
        node c;
        c.s.resize(s.size() + b.s.size());
        for (int i = 0; i < s.size(); i++)
            for (int j = 0; j < b.s.size(); j++)
                c.s[i + j] += s[i] * b.s[j];
        for (int i = 0; i < c.s.size() - 1; i++)
        {
            c.s[i + 1] += c.s[i] / BASE;
            c.s[i] %= BASE;
        }
        while (c.s.back() == 0 && c.s.size() > 1)
            c.s.pop_back();
        return c;
    }
    friend istream &operator>>(istream &input, node &x)
    {
        string s;
        if (!(input >> s))
            return input;
        x = s;
        return input;
    }
    friend ostream &operator<<(ostream &output, const node &x)
    {
        output << x.s.back();
        for (int i = x.s.size() - 2; i >= 0; i--)
        {
            char buf[20];
            sprintf(buf, "%08d", x.s[i]);
            for (int j = 0; j < strlen(buf); j++)
                output << buf[j];
        }
        return output;
    }
};
node Copy(const node &b, int x)
{
    node t;
    t.s.resize(b.s.size() + x);
    for (int i = 0; i < b.s.size(); i++)
        t.s[i + x] = b.s[i];
    return t;
}
node Divide(const node &a, const node &b, node &mod)
{
    node c;
    c.s.resize(a.s.size() - b.s.size() + 1);
    mod = a;
    int Pow[(int)log2(node::BASE) + 5];
    Pow[0] = 1;
    for (int i = 1; i <= log2(node::BASE); i++)
        Pow[i] = Pow[i - 1] * 2;
    for (int i = c.s.size() - 1; i >= 0; i--)
    {
        node t;
        t = Copy(b, i);
        for (int j = log2(node::BASE); j >= 0; j--)
            if (mod >= t * Pow[j])
            {
                c.s[i] += Pow[j];
                mod -= t * Pow[j];
            }
    }
    while (c.s.back() == 0 && c.s.size() > 1)
        c.s.pop_back();
    return c;
}
node a, b;
int main()
{
    cin >> a >> b;
    if (a < b)
        cout << a + b << endl << '-' << b - a << endl<< a * b << endl << 0 << endl << a << endl;
    else
    {
        node c, d;
        c = Divide(a, b, d);
        cout << a + b << endl << a - b << endl << a * b << endl << c << endl << d << endl;
    }
    return 0;
}
View Code

 三十七、急速素数判断(用6来判断的神奇性质)

bool Is_prime(int n)
{
    if(n==1) return false;
    if(n==2||n==3) return true;
    if(n%6!=1&&n%6!=5) return false;
    for(register int i=5;i*i<=n;i+=6)
        if(n%i==0||n%(i+2)==0) return false;
    return true;
}
View Code

三十八、字典树(用于查找前缀相同的字串)(其实我是想用邻接表硬模拟的233)

插入一个字符:

inline void update(string x)//要更新的字符串
{
    int u=0,tt;//u为节点,初始为0
    for( int i=0;i<x.size();i++)//扫描字串
    {
        tt=x[i]-'a';//手动转换
        if(!t[u][tt])//新建节点
        {
            t[u][tt]=++tot;
        }
        u=t[u][tt];
    }
    vis[u]=1;//对一个字串的截止加标记
}
View Code

遍历字典树:

inline void solve(string x)//遍历字典树,寻找是否存在一个字符串为当前串的前缀
{
    int u=0,tt;//依然,u是节点数
    for( int i=0;i<x.size();i++)//对当前串进行遍历
    {
        tt=x[i]-'a';
        if(vis[u])//如果存在一个串,前面都重合,然后有结束标记
        {
            f=1;//标记
            return;//结束遍历
        }
        u=t[u][tt];//到下个节点,儿子节点
    }
}
View Code

 三十九、单调队列(维护定长区间最值,优化dp)(对内的元素,元素下标都具有单调性,维护dp常消掉一个n的复杂度)

数组实现:

struct node
{
       int id,x;//存下标,值
}q[maxn];
int l=1,r=0;//初始化队列
for(int i=1;i<=n;i++)
{
    if(l>r)//如果队列为空
    printf("0
");
    else
    {
        if(q[l].id+m<i)//如果当前值已经"过时”
        l++;//弹掉
        printf("%d
",q[l].x);
    }
    while(l<=r&&q[r].x<=a[i])//维护单调
    r--;
    r++;//入队
    q[r].x=a[i];
    q[r].id=i;
}
 
View Code

四十、背包选讲(特别鸣谢:https://blog.csdn.net/weixin_43693379/article/details/89432283)

 1、01背包:

最基础的背包,最基础的动态规划。

朴素解法:$f[i][j]$表示第i个选或不选,占用空间是j个,所获得的最大价值。

#include <bits/stdc++.h>
namespace std;
#define N 1005int dp[N][N];//dp[i][j]表示前i个物品,背包容量是j的情况下的最大价值。
int w[N];//w表示价值
int v[N];//v表示体积
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &v[i], &w[i]);
    for (int i = 1; i <= n; i++)//枚举当前物品
    {
        for (int j = 0; j <= m; j++)//枚举剩余空间
        {
            dp[i][j] = dp[i - 1][j];
            if (j >= v[i])//只有剩余空间大于当前物品
                dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);//才能转移
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}
View Code

事实上,可以观察发现当前的空间只从上一维转移,所以可以考虑用滚动数组优化,j维倒序枚举,就能进行压维转移了。:

#include <iostream>
using namespace std;
#define N 1005
int dp[N];
int main()
{
    int n, m, v, w;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> v >> w;
        for (int j = m; j >= v; j--) //省下了if,剩余同上
        {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
    cout << dp[m] << endl;
    return 0;
}
View Code

这时的dp[i]表示空间<=i的最大价值,初始值均为0,所以如果存在一个k<m 使得空间最大为k的情况下dp[k]有最大价值,那么dp[m]一定可以从k这个状态转移过来—即dp[m]一定是最大值。
若题目要求装满背包,即将物品恰装入一个容量为m的背包中,只需要将初始化条件改一改即可,----将dp数组初始化为负无穷,dp[0]=0,即可确保状态一定是从0转移过来的。

 2、完全背包:

给定n个物品,每个物品有无限个数,求最大值

$f[i][j]$表示与01背包同样的意义,但是转移不是从前面一个进行转移了,而是从上一个自己进行转移。

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 1005
int dp[N][N];
int w[N];
int v[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &v[i], &w[i]);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j <= m; j++)
        {
            dp[i][j] = dp[i - 1][j];
            if (j >= v[i])
                dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]);
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}
View Code

事实上,也可以进行01背包类似的压维操作,只不过需要从自己转移,所以第二维需要正序进行

for (int i = 1; i <= n; i++)
    {
        cin >> v >> w;
        for (int j = v; j <= m; j++)
        {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
View Code

3、多重背包:

每个物品有s个,求最大价值

同01背包,只要加一个数量枚举即可。

还有二进制优化,实在是不会。

4、混合背包:

物品有1个的,多个的,无限的,求最大价值

如果是多重背包,就转成01背包,无限物品就弄成完全背包,按照标记跑就行了。

5、二维费用背包

背包有容量,重量限制(二重限制),求最大价值

其实,和01背包没什么区别,只需要多一重枚举(重量)就可以了。

#include <bits/stdc++.h>
using namespace std;
#define N 1005
int dp[N][N];
int main()
{
    int n, V, M, v, w, m;
    cin >> n >> V >> M;
    for (int i = 0; i < n; i++)
    {
        cin >> v >> m >> w;
        for (int j = V; j >= v; j--)
        {
            for (int k = M; k >= m; k--)
                dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w);
        }
    }
    cout << dp[V][M] << endl;
    return 0;
}
View Code

6、分组背包:

物品分为多组,组内只能选一个,求最大价值

抽象为价格不一样的多重背包,加一重循环即可,无优化。

#include<bits/stdc++.h>
using namespace std;
#define N 105
int dp[N];
int v[N];
int w[N];
int main()
{
    int n, m, s;
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        cin >> s;
        for (int k = 0; k < s; k++)
            cin >> v[k] >> w[k];
        for (int j = m; j >= 0; j--)
            for (int k = 0; k < s; k++)
                if (j >= v[k])
                    dp[j] = max(dp[j], dp[j - v[k]] + w[k]);
    }

    cout << dp[m] << endl;
    return 0;
}
View Code

7、树形背包:

每个物品有先行限制,只有解锁了上个,下个才能用,求最大价值。

树形dp,方程式一样,需要注意一下

void dfs(int x)
{
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        dfs(v);
        for (int j = m; j >= 0; j--)
        {
            for (int k = 0; k <= j; k++)
                dp[x][j] = max(dp[x][j], dp[x][j - k] + dp[v][k]);
        }
    }
    for (int i = m; i >= 0; i--)
        if (i >= v[x])
            dp[x][i] = dp[x][i - v[x]] + w[x];
        else //注意,父节点不选的话,子节点一个都不能选
            dp[x][i] = 0;
}
View Code

8、背包求方案数、

同01背包,只需要加一个记录方案的数组即可。

$num[i]$表示体积小于等于i的的方案数。

for (int i = 1; i <= n; i++)
{
    for (int j = m; j >= v[i]; j--)
    {
        if (dp[j - v[i]] + w[i] > dp[j])
        {
            dp[j] = dp[j - v[i]] + w[i];
            num[j] = num[j - v[i]];//如果可以更新一个更优解,则方案数直接继承
        }
        else if (dp[j - v[i]] + w[i] == dp[j])
            num[j] = (num[j] + num[j - v[i]]) % mod;//如果相等,那么加上之前的方案数
    }
}
View Code

9、背包求方案

01 ,方案输出,输出字典序最小的方案。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1005;
int dp[N][N], v[N], w[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &v[i], &w[i]);
    for (int i = n; i >= 1; i--)
    {
        for (int j = m; j >= 0; j--)
        {
            dp[i][j] = dp[i + 1][j];
            if (j >= v[i])
                dp[i][j] = max(dp[i][j], dp[i + 1][j - v[i]] + w[i]);
        }//01背包
    }
    int val = m;
    for (int i = 1; i <= n; i++)
    {
        if (val - v[i] >= 0 && dp[i][val] == dp[i + 1][val - v[i]] + w[i])//从小开始枚举,倒序还原dp过程,直接输出即可
        {
            cout << i << " ";
            val -= v[i];
        }
    }
    return 0;
}
View Code

 四十一、进制转换(负数为基底也可以)

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
int q, r;
char la[20] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
void f(int n, int m)
{
    if (n == 0)
        return;
    else
    {
        if (n > 0 || n % m == 0)
        {
            f(n / m, m);
            printf("%c", la[n % m]);
            return;
        }
        else
        {
            f(n / m + 1, m);
            printf("%c", la[-m + n % m]);
            return;
        }
    }
}
int main()
{
    scanf("%d", &q);
    scanf("%d", &r);
    printf("%d=", q);
    f(q, r);
    printf("(base%d)", r);
    system("pasue");
    system("pasue");
    return 0;
}
View Code

 

2333

原文地址:https://www.cnblogs.com/ajmddzp/p/11709671.html