• 可爱的模板们


    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

  • 相关阅读:
    QT内置的ICON资源
    Spark源代码阅读笔记之MetadataCleaner
    Android API Guides---Bluetooth
    做一个WINDOWS下破解WIFI。不须要Linux抓包!
    CPU GPU设计工作原理《转》
    杭电 1280 前m大的数
    机房收费系统——报表(2)
    概览C++之const
    Android动态禁用或开启屏幕旋转工具
    shrink-to-fit(自适应宽度)
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11709671.html
Copyright © 2020-2023  润新知