zoukankan      html  css  js  c++  java
  • 板子-GOD BLESS ALL OF YOU

    字符串:

    KMP

    #include<cstdio>
    #include<cstring>
    
    const int N=1000004;
    
    char s1[N],s2[N/100];
    int next[N/100];
    
    int l1,l2;
    
    void get_next()
    {
        next[0]=-1;
        for(int i=2,j=0;i<=l2;++i)
        {
            for(;s2[i]!=s2[j+1]&&j>0;j=next[j]);
            if(s2[i]==s2[j+1])next[i]=++j;
        }
    }
    
    void kmp()
    {
        for(int i=1,j=0;i<=l1;i++)
        {
            for(;s1[i]!=s2[j+1]&&j>0;j=next[j]);
            if(s1[i]==s2[j+1])++j;
            if(j==l2)
                printf("%d
    ",i-l2+1),j=next[l2];
        }
    }
    int main()
    {
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1);
        l2=strlen(s2+1);
        get_next();
        kmp();
        for(int i=1;i<=l2;i++)
        {
            printf("%d ",next[i]);
        }
        return 0;
    }
    kmp

    AC自动机last指针版

    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int  maxn = 100001;
    int n;
    char s[maxn][101];
    char ss[maxn*10];
    int ans=0;
    struct Aho_Corasick_automato {
        int sz;
        int ch[maxn][26];
        int cnt[maxn];
        int val[maxn];
        int last[maxn];
        int fail[maxn];
        int num;
        void init() {
            memset(ch[0],0,sizeof(ch[0]));
            memset(cnt,0,sizeof(cnt));
            sz=1;
        }
        void insert(char *s,int num) {
            int len=strlen(s);
            int u=0;
            for(int i=0; i<len; ++i) {
                int v=(s[i]-'a');
                if(!ch[u][v]) {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz]=0;
                    ch[u][v]=sz++;
                }
                u=ch[u][v];
            }
            val[u]=num;
        }
        void get_fail() {
            fail[0]=0;
            queue<int>que;
            for(int i=0; i<26; i++) {
                int u=ch[0][i];
                if(u) {
                    fail[u]=0;
                    que.push(u);
                }
            }
            while(!que.empty()) {
                int u=que.front();
                que.pop();
                for(int i=0; i<26; i++) {
                    int v=ch[u][i];
                    if(!v) {
                        ch[u][i]=ch[fail[u]][i];
                        continue;
                    }
                    que.push(v);
                    int k=fail[u];
                    fail[v]=ch[k][i];
                    last[v]=val[fail[v]] ? fail[v] : last[fail[v]];
                }
            }
        }
        void work(int x) {
            if(x) {
                cnt[val[x]]++;
                work(last[x]);
            }
        }
        void find(char *s) {
            int len=strlen(s);
            int u=0;
            for(int i=0; i<len; i++) {
                int v=(s[i]-'a');
                if(!ch[u][v])u=fail[u];
                while(u&&!ch[u][v])
                    u=fail[u];
                u=ch[u][v];
                if(val[u])
                    work(u);
                else if(last[u])
                    work(last[u]);
            }
        }
    } ac;
    
    int main() {
    
    
        while(scanf("%d",&n)==1&&n!=0) {
            ac.init();
            for(int i=1; i<=n; i++) {
                scanf("%s",s[i]);
                ac.insert(s[i],i);
            }
            ac.get_fail();
            scanf("%s",ss);
            ac.find(ss);
            int ans=0,r;
            for(int i=1;i<=n;i++)
                if(ac.cnt[i]>ans)ans=ac.cnt[i],r=i;;
            printf("%d
    ",ans);
             for(int r=1;r<=n;r++)
                if(ac.cnt[r]==ans)
                    printf("%s
    ",s[r]);
            }
        return 0;
    }
    AC自动机

    马拉车

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 33000000
    
    int n,p[N],ans;
    char s[N],str[N];
    void manachar() 
    {
        int mx=0,id;
        for(int i=n; str[i]!=0; i++)str[i]=0;
        for(int i=1; i<n; i++) 
        {
            if(mx>i)
                p[i]=min(p[2*id-i],p[id]+id-i);
            else 
                p[i]=1;
            for(;str[i+p[i]]==str[i-p[i]];++p[i]);
            if(p[i]+i>mx) 
                mx=p[i]+i,
                id=i;
        }
    }
    void csh()
    {
        str[0]='#';
        str[1]='#';
        for(int i=0;i<n;i++)
        str[(i<<1)+2]=s[i],str[(i<<1)+3]='#';
        n=(n<<1)+2;
        str[n]=0;
    }
    int main() {
        scanf("%s",s);
        n=strlen(s);
        csh();
        manachar();
        ans=0;
        for(int i=0;i<n;i++)
            ans=max(ans,p[i]);
        printf("%d
    ",ans-1);
        return 0;
    }
    manacher

     字符串hash

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef unsigned long long ull;
    ull base = 131;
    char s[100000];
    ull a[100000];
    ull hashs(char *s)
    {
        int len=strlen(s);
        ull ans=0;
        for(int i=0;i<len;i++)
            ans=ans*base+(ull)s[i];
        return ans&0x7fffffff;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%s",s);
            a[i]=hashs(s);
        }
        sort(a+1,a+n+1);
        int ans=0;
        for(int i=2;i<=n;i++)
             if(a[i]!=a[i-1]) ans++;
        printf("%d
    ",++ans);
        return 0;
    }
    字符串hash

     后缀数组

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using std::swap;
    const int maxn=2000010;
    
    char c[maxn];
    int s[maxn],sa[maxn];//后缀排名的位置
    int rank[maxn];//后缀排名
    int height[maxn];//常规操作
    int saf[maxn];//用saf[]作为第2关键字后缀的第一关键字
    int cs[maxn];//基数排序中的排名计数器
    int n,m;
    void rsort() {//第二关键字基数排序
        for(int i=0;i<=m;++i)cs[i]=0;
        for(int i=1;i<=n;++i)cs[rank[saf[i]]]++;
        for(int i=1;i<=m;++i)cs[i]+=cs[i-1];
        for(int i=n;i>=1;--i)sa[cs[rank[saf[i]]]--]=saf[i];//利用第二关键字排名更新sa
    }
    int cmp(int *f,int x,int y,int w) {
        return f[x]==f[y]&&f[x+w]==f[y+w];//cmp 
    }
    void get_sa() {
        for(int i=1;i<=n;++i)rank[i]=s[i],saf[i]=i;//此时saf[i]指向自己作为第一关键字的后缀
        m=127;rsort();
        for(int p=1,w=1,i;p<n;w<<=1,m=p) {//w为倍增长度,<选取第几位作为第二关键字>
            for(i=n-w+1,p=0;i<=n;++i)saf[++p]=i;
            for(i=1;i<=n;++i)if(sa[i]>w)saf[++p]=sa[i]-w;//利用上次的sa[]值更新下一次的saf[],有的字母已经不能再作为后缀的第n位的关键字了0
            rsort();swap(rank,saf);rank[sa[1]]=p=1;//p用来记录已经不需要再比较'第三关键字的'的后缀//当p=n是说明排序完成
            for(i=2;i<=n;++i)rank[sa[i]]=cmp(saf,sa[i],sa[i-1],w)?p:++p;//比较第一关键词与自己排名相临的,若第二关键字相同则需继续比较
        }
        //int j,k=0;
        //for(int i=1;i<=n;height[rank[i++]]=k)
          //  for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
    }
    int main() {
        scanf("%s",c+1);
        n=strlen(c+1);
        for(int i=1;i<=n;++i)s[i]=c[i];
        s[0]=s[n+1]=-1;
        get_sa();
        for(int i=1;i<=n;++i) {
            printf("%d ",sa[i]);
        }
        return 0;
    }
    后缀数组

    数据结构

    手写heap

    void put(int r) 
    {
        while(r>1&&a[r]<a[r/2]) 
        {
            h=a[r];
            a[r]=a[r/2];
            a[r/2]=h;
            r/=2;
        }
    }
    int flag=1;
    int get()//弹出最小值 
    {
        if(flag==1)
        {
            sum=a[1];
            flag=0;
        }
        else sum+=a[1];
        a[1]=a[len];
        len--;
        r=1;
        while((r*2<=len&&a[r]>a[r*2])||(r*2+1<=len&&a[r]>a[r*2+1]))
            {
                j=r*2;
                if(j+1<=len&&a[j]>a[j+1])j++;
                h=a[r];
                a[r]=a[j];
                a[j]=h;
                r=j;
            }
    }
    heap

    树状数组

    1单点修改+区间查询

    //树状数组:区间查询,单点修改 
    #include<cstdio>
    int sum[500100];
    int n,m;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x,int v)
    {
        while (x<=n)
        {
            sum[x] += v;
            x += lowbit(x);
        }
    }
    int query(int x)
    {
        int ans = 0;
        while (x)
        {
            ans += sum[x];
            x -= lowbit(x);
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int a,i=1; i<=n; ++i)
        {
            scanf("%d",&a);
            update(i,a);
        }
        for (int i=1; i<=m; ++i)
        {
            int x,y,z;
            scanf("%d%d%d",&z,&x,&y);
            if (z==1) update(x,y);    //单点修改 
            else printf("%d
    ",query(y)-query(x-1));
        }
        return 0;
    }
    树状数组1

    2区间修改+单点查询

    //树状数组:区间修改,单点查询,差分 
    #include<cstdio>
    int sum[500100];
    int n,m,last = 0;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x,int v)
    {
        while (x<=n)
        {
            sum[x] += v;
            x += lowbit(x);
        }
    }
    int query(int x)
    {
        int ans = 0;
        while (x)
        {
            ans += sum[x];
            x -= lowbit(x);
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int a,i=1; i<=n; ++i)
        {
            scanf("%d",&a);
            update(i,a-last);
            last = a;
        }
        for (int x,y,z,a,i=1; i<=m; ++i)
        {
            scanf("%d",&a);
            if (a==1)    //区间修改
            {
                scanf("%d%d%d",&x,&y,&z);
                update(x,z);
                update(y+1,-z); 
            } 
            else        //单点查询 
            {
                scanf("%d",&x);
                printf("%d
    ",query(x));
            }
        }
        return 0;
    }
    树状数组2

    可持久化线段树(状态区间和)

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define N 100001
    int n,m,cnt,ans;
    int root[N*20];
    int ls[N*20],sum[N*20],rs[N*20];
    int ope[N];
    void change(int l,int r,int &rt,int pre,int pos,int w)
    {
        if(!rt)rt=++cnt;
        sum[rt]=sum[pre];
        if(l==r){sum[rt]=w;return;}
        int mid=(l+r)>>1;
        if(pos<=mid)rs[rt]=rs[pre],change(l,mid,ls[rt],ls[pre],pos,w);
        else ls[rt]=ls[pre],change(mid+1,r,rs[rt],rs[pre],pos,w);
        sum[rt]=sum[ls[rt]]+sum[rs[rt]];
    }
    void query(int l,int r,int rt,int opl,int opr)
    {
        if(opl<=l&&opr>=r){
            ans+=sum[rt];return ;
        }
        int mid=(l+r)>>1;
        if(opl<=mid)query(l,mid,ls[rt],opl,opr);
        if(opr>mid)query(mid+1,r,rs[rt],opl,opr);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        int x,y,z;
        for(int i=1;i<=n;i++)
        scanf("%d",&x),change(1,n,root[0],root[0],i,x);
        char s[3];
        int now=0;
        for(int i=1;i<=m;i++)
        {
            ope[i]=now;
            scanf("%s",s);
            if(s[0]=='M')
            {
                now++;
                ope[i]=now;
                scanf("%d%d",&x,&y);
                change(1,n,root[now],root[now-1],x,y);
            }
            else 
            {
                scanf("%d%d%d",&x,&y,&z);
                ans=0;
                query(1,n,root[ope[z]],x,y);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    可持久化线段树

    主席树k大值

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 100001;
    int ls[N*20],rs[N*20],sum[N*20];
    int n,m,a[N],hash[N],cnt,root[N];
    int x,y,k;
    void lsh()
    {
        sort(hash+1,hash+n+1);
        cnt=unique(hash+1,hash+n+1)-(hash+1);
        for(int i=1;i<=n;i++)a[i]=lower_bound(hash+1,hash+cnt+1,a[i])-hash;
    }
    int tot=0;
    void build(int l,int r,int &rt,int pre,int w)
    {
        rt=++tot;
        sum[rt]=sum[pre]+1;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(w<=mid)rs[rt]==rs[pre],build(l,mid,ls[rt],ls[pre],w);
        else ls[rt]=ls[pre],build(mid+1,r,rs[rt],rs[pre],w);
    }
    int query(int l,int r,int x,int y,int k)
    {
        if(l==r)return l;
        int mid=l+r>>1,tmp=sum[ls[y]]-sum[ls[x]];
        if(tmp>=k)return query(l,mid,ls[x],ls[y],k);
        else return query(mid+1,r,rs[x],rs[y],k-tmp);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",a+i),hash[i]=a[i];
        lsh();
    //    printf("%d
    ",cnt);for(int i=1;i<=cnt;i++) printf("%d ",hash[i]);
        for(int i=1;i<=n;i++) build(1,cnt,root[i],root[i-1],a[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&k);
            printf("%d
    ",hash[query(1,cnt,root[x-1],root[y],k)]);
        }
        return 0;
    }
    主席树

    Splay tree 区间翻转区间标记

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define N 100005
    int n,m;
    struct node{
        int siz,fa,ch[2];//0zuo,1you;
        bool rev;
    }tr[N];
    int root;
    void push_down(int rt)
    {
        if(tr[rt].rev)
        {
            swap(tr[rt].ch[1],tr[rt].ch[0]);
            tr[rt].rev=0;
            tr[tr[rt].ch[0]].rev^=1;tr[tr[rt].ch[1]].rev^=1;
        }
    }
    void pushup(int rt)
    {
        tr[rt].siz=tr[tr[rt].ch[0]].siz+tr[tr[rt].ch[1]].siz+1;
        return;
    }
    int find(int rt,int x)
    {
        if(rt==0)return 0;
        push_down(rt);
        if(x<=tr[tr[rt].ch[0]].siz)return find(tr[rt].ch[0],x);
        if(x==tr[tr[rt].ch[0]].siz+1)return rt;
        return find(tr[rt].ch[1],x-tr[tr[rt].ch[0]].siz-1);
    }
    void rotate(int &rt,int x)
    {
        int y=tr[x].fa,q=tr[y].fa;
        bool dy=tr[y].ch[1]==x,dz=tr[q].ch[1]==y;
        push_down(y);
        if(rt==y)rt=x,tr[x].fa=q;
        else tr[q].ch[dz]=x,tr[x].fa=q;
        tr[y].ch[dy]=tr[x].ch[dy^1],tr[tr[x].ch[dy^1]].fa=y;
        tr[x].ch[dy^1]=y,tr[y].fa=x;
        pushup(y);
        return ;
    }
    void splay(int &rt,int x)
    {
        push_down(x);
        while(rt!=x)
        {
            int y=tr[x].fa;int q=tr[y].fa;
            if(y!=rt)
            {
                if(tr[y].ch[1]==x^tr[q].ch[1]==y)rotate(rt,x);
                else rotate(rt,y);
            }
            rotate(rt,x);
        }
        pushup(x);
        return;
    }
    void print(int rt)
    {
        if(rt==0)return;
        push_down(rt);
        print(tr[rt].ch[0]);
        if(rt>1&&rt<n+2)printf("%d ",rt-1);
        print(tr[rt].ch[1]);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n+2;i++)
        {
            tr[i].siz=n+3-i;tr[i].fa=i-1;tr[i].ch[1]=i+1;
        }
        tr[n+2].ch[1]=0,root=1;
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            splay(root,find(root,l));
            splay(tr[root].ch[1],find(root,r+2));
            tr[tr[tr[root].ch[1]].ch[0]].rev^=1;
        }
        print(root);
        return 0;
    }
    splay区间

    Splay基本操作插入,删除,k大,值rank,前驱,后继

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define N 100005
    int n,m;
    struct node{
        int siz,fa,ch[2];//0zuo,1you;
        bool rev;
    }tr[N];
    int root;
    void push_down(int rt)
    {
        if(tr[rt].rev)
        {
            swap(tr[rt].ch[1],tr[rt].ch[0]);
            tr[rt].rev=0;
            tr[tr[rt].ch[0]].rev^=1;tr[tr[rt].ch[1]].rev^=1;
        }
    }
    void pushup(int rt)
    {
        tr[rt].siz=tr[tr[rt].ch[0]].siz+tr[tr[rt].ch[1]].siz+1;
        return;
    }
    int find(int rt,int x)
    {
        if(rt==0)return 0;
        push_down(rt);
        if(x<=tr[tr[rt].ch[0]].siz)return find(tr[rt].ch[0],x);
        if(x==tr[tr[rt].ch[0]].siz+1)return rt;
        return find(tr[rt].ch[1],x-tr[tr[rt].ch[0]].siz-1);
    }
    void rotate(int &rt,int x)
    {
        int y=tr[x].fa,q=tr[y].fa;
        bool dy=tr[y].ch[1]==x,dz=tr[q].ch[1]==y;
        push_down(y);
        if(rt==y)rt=x,tr[x].fa=q;
        else tr[q].ch[dz]=x,tr[x].fa=q;
        tr[y].ch[dy]=tr[x].ch[dy^1],tr[tr[x].ch[dy^1]].fa=y;
        tr[x].ch[dy^1]=y,tr[y].fa=x;
        pushup(y);
        return ;
    }
    void splay(int &rt,int x)
    {
        push_down(x);
        while(rt!=x)
        {
            int y=tr[x].fa;int q=tr[y].fa;
            if(y!=rt)
            {
                if(tr[y].ch[1]==x^tr[q].ch[1]==y)rotate(rt,x);
                else rotate(rt,y);
            }
            rotate(rt,x);
        }
        pushup(x);
        return;
    }
    void print(int rt)
    {
        if(rt==0)return;
        push_down(rt);
        print(tr[rt].ch[0]);
        if(rt>1&&rt<n+2)printf("%d ",rt-1);
        print(tr[rt].ch[1]);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n+2;i++)
        {
            tr[i].siz=n+3-i;tr[i].fa=i-1;tr[i].ch[1]=i+1;
        }
        tr[n+2].ch[1]=0,root=1;
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            splay(root,find(root,l));
            splay(tr[root].ch[1],find(root,r+2));
            tr[tr[tr[root].ch[1]].ch[0]].rev^=1;
        }
        print(root);
        return 0;
    }
    splay

    treap

    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #define N 500007
    int inline read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int tree[N][2],val[N],key[N],siz[N],sz;
    inline void update(int x) {
        siz[x]=1+siz[tree[x][0]]+siz[tree[x][1]];
    }
    int make_new(int v) {
        siz[++sz]=1;
        val[sz]=v;
        key[sz]=rand();
        return sz;
    }
    int merge(int x,int y) {
        if(!x) return y;
        else if(!y)return x;
        if(key[x]<key[y]) {
            tree[x][1]=merge(tree[x][1],y);
            update(x);
            return x;
        }
        else {
            tree[y][0]=merge(x,tree[y][0]);
            update(y);
            return y;
        }
    }
    void split(int now,int k,int &x,int &y) {//根据插入数的val值,把树分为小于等于k的,和大于k的 
        if (!now) x=y=0;//指针为空 
        else {
            if (val[now]<=k)
                x=now,split(tree[now][1],k,tree[now][1],y);//访问右子树 
            else
                y=now,split(tree[now][0],k,x,tree[now][0]);//访问左子树 
            update(now);
        }
    }
    int kth(int now,int k) {
        while(1) {
            if (k<=siz[tree[now][0]])
                now=tree[now][0];
            else
            if (k==siz[tree[now][0]]+1)
                return now;
            else
                k-=siz[tree[now][0]]+1,now=tree[now][1];
        }
    }
    int main() {
        //srand((unsigned)time(NULL));
        int T,op,x,y,z,a,b,root=0;
        scanf("%d",&T);
        while(T--) {
            op=read(),a=read();
            if (op==1) {
                split(root,a,x,y);
                root=merge(merge(x,make_new(a)),y);
            }
            else
            if (op==2) {
                split(root,a,x,z);
                split(x,a-1,x,y);
                y=merge(tree[y][0],tree[y][1]);
                root=merge(merge(x,y),z);
            }
            else if (op==3) {
                split(root,a-1,x,y);
                printf("%d
    ",siz[x]+1);
                root=merge(x,y);
            }
            else if (op==4)
                printf("%d
    ",val[kth(root,a)]);
            else
            if (op==5) {
                split(root,a-1,x,y);
                printf("%d
    ",val[kth(x,siz[x])]);
                root=merge(x,y);
            }
            else {
                split(root,a,x,y);
                printf("%d
    ",val[kth(y,1)]);
                root=merge(x,y);
            }
        }
        return 0;
    }
    treap

    树链剖分(树上求和/树上最值)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 using namespace std;
      5 const int MAXN=2*1e6+10;
      6 #define ls k<<1
      7 #define rs k<<1|1
      8 inline int read() {
      9     char c=getchar();
     10     int x=0,f=1;
     11     while(c<'0'||c>'9') {
     12         if(c=='-')f=-1;
     13         c=getchar();
     14     }
     15     while(c>='0'&&c<='9') 
     16         x=x*10+c-'0',c=getchar();
     17     return x*f;
     18 }
     19 struct node {
     20     int u,v,nxt;
     21 } edge[MAXN];
     22 int head[MAXN];
     23 int num=1;
     24 struct Tree {
     25     int l,r,w,siz,f;
     26 } T[MAXN];
     27 int N,M,root,MOD,cnt=0,a[MAXN],b[MAXN];
     28 inline void AddEdge(int x,int y) {
     29     edge[num].u=x;
     30     edge[num].v=y;
     31     edge[num].nxt=head[x];
     32     head[x]=num++;
     33 }
     34 int deep[MAXN],fa[MAXN],son[MAXN],tot[MAXN],top[MAXN],idx[MAXN];
     35 int dfs1(int now,int f,int dep) {
     36     deep[now]=dep;
     37     fa[now]=f;
     38     tot[now]=1;
     39     int maxson=-1;
     40     for(int i=head[now]; i!=-1; i=edge[i].nxt) {
     41         if(edge[i].v==f) continue;
     42         tot[now]+=dfs1(edge[i].v,now,dep+1);
     43         if(tot[edge[i].v]>maxson) maxson=tot[edge[i].v],son[now]=edge[i].v;
     44     }
     45     return tot[now];
     46 }
     47 void update(int k) {
     48     T[k].w=(T[ls].w+T[rs].w+MOD)%MOD;
     49 }
     50 void Build(int k,int ll,int rr) {
     51     T[k].l=ll;
     52     T[k].r=rr;
     53     T[k].siz=rr-ll+1;
     54     if(ll==rr) {
     55         T[k].w=a[ll];
     56         return ;
     57     }
     58     int mid=(ll+rr)>>1;
     59     Build(ls,ll,mid);
     60     Build(rs,mid+1,rr);
     61     update(k);
     62 }
     63 void dfs2(int now,int topf) {
     64     idx[now]=++cnt;
     65     a[cnt]=b[now];
     66     top[now]=topf;
     67     if(!son[now]) return ;
     68     dfs2(son[now],topf);
     69     for(int i=head[now]; i!=-1; i=edge[i].nxt)
     70         if(!idx[edge[i].v])
     71             dfs2(edge[i].v,edge[i].v);
     72 }
     73 void pushdown(int k) {
     74     if(!T[k].f) return ;
     75     T[ls].w=(T[ls].w+T[ls].siz*T[k].f)%MOD;
     76     T[rs].w=(T[rs].w+T[rs].siz*T[k].f)%MOD;
     77     T[ls].f=(T[ls].f+T[k].f)%MOD;
     78     T[rs].f=(T[rs].f+T[k].f)%MOD;
     79     T[k].f=0;
     80 }
     81 void IntervalAdd(int k,int ll,int rr,int val) {
     82     if(ll<=T[k].l&&T[k].r<=rr) {
     83         T[k].w+=T[k].siz*val;
     84         T[k].f+=val;
     85         return ;
     86     }
     87     pushdown(k);
     88     int mid=(T[k].l+T[k].r)>>1;
     89     if(ll<=mid)    IntervalAdd(ls,ll,rr,val);
     90     if(rr>mid)    IntervalAdd(rs,ll,rr,val);
     91     update(k);
     92 }
     93 void TreeAdd(int x,int y,int val) {
     94     while(top[x]!=top[y]) {
     95         if(deep[top[x]]<deep[top[y]]) swap(x,y);
     96         IntervalAdd(1,idx[ top[x] ],idx[x],val);
     97         x=fa[ top[x] ];
     98     }
     99     if(deep[x]>deep[y])    swap(x,y);
    100     IntervalAdd(1,idx[x],idx[y],val);
    101 }
    102 int IntervalSum(int k,int ll,int rr) {
    103     int ans=0;
    104     if(ll<=T[k].l&&T[k].r<=rr)
    105         return T[k].w;
    106     pushdown(k);
    107     int mid=(T[k].l+T[k].r)>>1;
    108     if(ll<=mid) ans=(ans+IntervalSum(ls,ll,rr))%MOD;
    109     if(rr>mid)  ans=(ans+IntervalSum(rs,ll,rr))%MOD;
    110     return ans;
    111 }
    112 void TreeSum(int x,int y) {
    113     int ans=0;
    114     while(top[x]!=top[y]) {
    115         if(deep[top[x]]<deep[top[y]]) swap(x,y);
    116         ans=(ans+IntervalSum(1,idx[ top[x] ],idx[x]))%MOD;
    117         x=fa[ top[x] ];
    118     }
    119     if(deep[x]>deep[y]) swap(x,y);
    120     ans=(ans+IntervalSum(1,idx[x],idx[y]))%MOD;
    121     printf("%d
    ",ans);
    122 }
    123 int main() {
    124     memset(head,-1,sizeof(head));
    125     N=read(); M=read();
    126     root=read();
    127     MOD=read();
    128     for(int i=1; i<=N; i++) b[i]=read();
    129     for(int i=1; i<=N-1; i++) {
    130         int x=read(),y=read();
    131         AddEdge(x,y);
    132         AddEdge(y,x);
    133     }
    134     dfs1(root,0,1);
    135     dfs2(root,root);
    136     Build(1,1,N);
    137     while(M--) {
    138         int opt=read(),x,y,z;
    139         if(opt==1) {
    140             x=read();
    141             y=read();
    142             z=read();
    143             z=z%MOD;
    144             TreeAdd(x,y,z);
    145         } else if(opt==2) {
    146             x=read();
    147             y=read();
    148             TreeSum(x,y);
    149         } else if(opt==3) {
    150             x=read(),z=read();
    151             IntervalAdd(1,idx[x],idx[x]+tot[x]-1,z%MOD);
    152         } else if(opt==4) {
    153             x=read();
    154             printf("%d
    ",IntervalSum(1,idx[x],idx[x]+tot[x]-1));
    155         }
    156     }
    157     return 0;
    158 }
    sp

    link cut tree

      1 #include<cstdio>
      2 #include<algorithm>
      3 const int maxn = 320007;
      4 inline int read() {
      5     int x=0,f=1;char c=getchar();
      6     while(c<'0'||c>'9') {
      7         if(c=='-')f=-1;c=getchar();
      8     }
      9     while(c<='9'&&c>='0') {
     10         x=x*10+c-'0',c=getchar();
     11     }
     12     return x*f;
     13 }
     14 #define lc ch[x][0]
     15 #define rc ch[x][1]
     16 bool rev[maxn];
     17 int stack[maxn],top;
     18 int ans[maxn],v[maxn];
     19 int fa[maxn],ch[maxn][2];
     20 bool isroot(int x) {
     21     return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
     22 }
     23 void update(int x){
     24     ans[x]=ans[lc]^ans[rc]^v[x];
     25 }
     26 void pushdown(int x) {
     27      if(rev[x]) {
     28         rev[x]=0;rev[lc]^=1;rev[rc]^=1;
     29         std::swap(lc,rc);
     30      }
     31      return;
     32 }
     33 void rotate(int x) {
     34     int y=fa[x],z=fa[y],d=(ch[y][1]==x)^1;
     35     if(!isroot(y)) ch[z][ch[z][1]==y]=x;
     36     fa[x]=z;
     37     ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y;
     38     ch[x][d]=y;fa[y]=x;
     39     return update(y),update(x);
     40 }
     41 void splay(int x) {
     42     stack[++top]=x;
     43     for(int i=x;!isroot(i);i=fa[i]) 
     44         stack[++top]=fa[i];
     45     while(top)pushdown(stack[top--]);
     46     while(!isroot(x)) {
     47         int y=fa[x],z=fa[y];
     48         if(!isroot(y)) {
     49             if(ch[y][1]==x^ch[z][1]==y)rotate(x);
     50             else rotate(y);
     51         }
     52         rotate(x);
     53     }
     54     return ;
     55 }
     56 void access(int x) {
     57     for(int i=0;x;i=x,x=fa[x]) {
     58         splay(x),ch[x][1]=i,update(x);
     59     }
     60     return ;
     61 }
     62 void makeroot(int x) {
     63     access(x);splay(x);rev[x]^=1;
     64     return;
     65 }
     66 void split(int x,int y) {
     67     makeroot(x),access(y);return splay(y);
     68 }
     69 void cut(int x,int y) {
     70     split(x,y);
     71     ch[y][0]=fa[ch[y][0]]=0;
     72     return;
     73 }
     74 void link(int x,int y) {
     75     makeroot(x),fa[x]=y;return splay(x);
     76 }
     77 int find(int x) {
     78     for(access(x),splay(x);ch[x][0];x=ch[x][0]);
     79     return x;
     80 }
     81 int query(int x,int y) {
     82     split(x,y);
     83     return ans[y];
     84 }
     85 void modify(int x,int w) {
     86     access(x),splay(x),v[x]=w;
     87     return update(x);
     88 }
     89 int main() {
     90     int n,m;
     91     n=read(),m=read();
     92     for(int i=1;i<=n;++i) {
     93         v[i]=read();ans[i]=v[i];
     94     }
     95     for(int op,x,y,i=1;i<=m;++i) {
     96         op=read(),x=read(),y=read();
     97         if(!op) 
     98             printf("%d
    ",query(x,y));
     99         else if(op==1) {
    100             if(find(x)!=find(y)) link(x,y);
    101         }
    102         else if(op==2) {
    103             if(find(x)==find(y))cut(x,y);
    104         }
    105         else modify(x,y);
    106     }
    107     return 0;
    108 }
    lct

    左偏树

    #include<cstdio>
    #include<algorithm>
    
    inline int read() {
        int x=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
        return x;
    }
    const int maxn = 100010;
    struct node {
        int fa,dis,key,ch[2];
        node() {
            key=fa=dis=0;
        }
    }tree[maxn];
    inline int ls(int x) {return tree[x].ch[0];}
    inline int rs(int x) {return tree[x].ch[1];}
    int n,m;
    int find(int x) {
        if(tree[x].fa)  return find(tree[x].fa);
        else return x;
    }
    inline void update(int x) {
        tree[x].dis=tree[tree[x].ch[1]].dis+1;
    }
    int merge(int x,int y) {
        if(!x||!y)return x+y;
        if(tree[x].key>tree[y].key||(tree[x].key==tree[y].key&&x>y))std::swap(x,y);
        tree[x].ch[1]=merge(tree[x].ch[1],y);
        tree[tree[x].ch[1]].fa=x;
        if(tree[tree[x].ch[1]].dis>tree[tree[x].ch[0]].dis)std::swap(tree[x].ch[0],tree[x].ch[1]);
        update(x);
        return x;
    }
    void delet(int x) {
        int now=tree[x].fa;int top=merge(tree[x].ch[1],tree[x].ch[0]);
        tree[top].fa=now;tree[x].key=-1;
        while(now) {
            if(tree[tree[now].ch[0]].dis<tree[tree[now].ch[1]].dis)std::swap(tree[now].ch[0],tree[now].ch[1]);
            if(tree[now].dis==tree[tree[now].ch[1]].dis+1)return;
            tree[now].dis=tree[tree[now].ch[1]].dis+1;
            now=tree[now].fa;
        }
    }
    int main() {
        n=read(),m=read();
        for(int i=1;i<=n;++i) tree[i].key=read();
        while(m--) {
            int op=read();
            if(op==1) {
                int x=read(),y=read();
                if(tree[x].key==-1||tree[y].key==-1||x==y)continue;
                merge(find(x),find(y));
            }
            else {
                int x=read();
                if(tree[x].key==-1)puts("-1");
                else x=find(x),
                printf("%d
    ",tree[x].key),
                delet(x);
            }
        }
        return 0; 
    }
    左偏树

    单调队列(两端扩展最大距离(最小值))

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define LL long long 
    const int maxn= 2000007;
    #ifdef WIN32
    #define lld "I64d"
    #else
    #define lld "lld"
    #endif
    inline int read() {
        int x=0;
        char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();return x;
    } 
    int a[maxn],b[maxn];
    int l[maxn],r[maxn],tmp[maxn],q[maxn];
    int n,m;
    void work(int c[] ,int d[]) {
        q[1]=c[1]; tmp[1]=1;
        int head=1,tail=1;
        for(int i=2;i<=n;++i) {
            while(head<=tail&&q[tail]>c[i]) d[tmp[tail--]]=i-1;
            q[++tail]=c[i];
            tmp[tail]=i;
           }
           while(head<=tail) d[tmp[head++]]=n;
    }
    int main() {
        LL ans=0;
        n=read();
        for(int i=1;i<=n;++i) 
            a[i]=read(),b[n-i+1]=a[i];
        work(a,r);
        work(b,l);
        for(int i=1;i<=n;++i) tmp[i]=l[i];
        for(int i=1;i<=n;++i) l[n-i+1]=n-tmp[i]+1;
        for(int i=1;i<=n;++i) ans=max(ans,1ll*a[i]*(r[i]-l[i]+1));
        printf("%lld
    ",ans);
        return 0;
    }
    
    单调队列
    单调队列

     并查集安置合并

    int cnt = 0 ,fa[maxn],deep[maxn],siz[maxn],v[maxn]; 
    int find(int x)  { 
        if(fa[x] != x) { 
            int f = find(fa[x]); 
            deep[x] = deep[fa[x]] + 1; 
            return f;   
        } else return x; 
    } 
    void Union(int x,int y,int C) { 
        int f1 = find(x),f2 = find(y);  
        if(f1 == f2) return ;  
        if(siz[f1] > siz[f2]) fa[f2] = f1,v[f2] = C,siz[f1] += siz[f2]; 
        else fa[f1] = f2,v[f1] = C,siz[f2] += siz[f1]; 
    } 
    int query(int x,int y) {
        int f1 = find(x),f2 = find(y); 
        if(f1 != f2)return 0; 
        int ret = 0 ; 
        for(;x != y;) { 
            if(deep[x] < deep[y]) swap(x,y); 
            ret = max(ret,v[x]),x = fa[x]; 
        } return ret; 
    } 
    并查集

    AC自动机

    fail树

    #include<queue> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    #define LL long long
    inline int read() { 
        int x = 0,f = 1;char c = getchar(); 
        while(c < '0'||c > '9')c = getchar(); 
        while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
        return x * f; 
    } 
    #define LL long long 
    int n; 
    const int maxn = 1000097; 
    char a[maxn];
    int sz,ch[maxn][27];LL cnt[maxn]; 
    struct node {
        int v,next; 
    } edge[maxn << 1]; 
    int num,head[maxn],loc[maxn]; 
    inline void add_edge(int u,int v) { edge[++ num].v = v ;edge[num].next = head[u];head[u] = num; } 
    int insert(char *t) { 
        int len = strlen(t); 
        int now = 0; 
        for(int i = 0;i < len;++ i) { 
            int  s = t[i] - 'a'; 
            if(!ch[now][s]) ch[now][s] = ++ sz; 
            now = ch[now][s]; cnt[now] ++; 
        } 
        return now; 
    } 
    int fail[maxn],q[maxn]; 
    void get_fail(int l = 0,int r = 0 ) { 
        for(int i = 0;i <= 25;++ i)if(ch[0][i]) q[++ r] = ch[0][i]; 
        while(l < r) { 
            int u = q[++ l]; 
            for(int i = 0;i <= 25;++ i) { 
                int v = ch[u][i]; 
                if(v) fail[v] = ch[fail[u]][i],q[++ r] = v; 
                else ch[u][i] = ch[fail[u]][i]; 
            } 
        } 
    } 
    void dfs(int x,int fa = 0) {  
        for(int i = head[x];i;i = edge[i].next) {  
            int v = edge[i].v;  
            if(v != fa) {dfs(v,x),cnt[x] += cnt[v];}   
        }   
    }  
    int main() { 
        n = read();  
        for(int i = 1;i <= n;++ i) {  
            scanf("%s",a);  
            loc[i] = insert(a);  
        }  
        get_fail();  
        for(int i = 1;i <= sz;++ i) { 
            add_edge(fail[i],i); 
        } 
        dfs(0); 
        for(int i = 1;i <= n;++ i) { 
            printf("%d
    ",cnt[loc[i]]); 
        } 
        return 0;
    }
    ACfail树
    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int  maxn = 1000001;
    int n;
    char s[maxn];
    
    int ans=0;
    struct Aho_Corasick_automato{
        int sz;
        int ch[maxn][26];
        int val[maxn];
        int last[maxn];
        int fail[maxn];
        int num;
        void init() {
            memset(ch[0],0,sizeof(ch[0]));
            sz=1;
        }
        void insert(char *s) {
            int len=strlen(s);
            int u=0;
            for(int i=0; i<len; ++i) {
                int v=(s[i]-'a');
                if(!ch[u][v]) {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz]=0;
                    ch[u][v]=sz++;
                }
                u=ch[u][v];
            }
            val[u]++;
        }
        void get_fail() {
            fail[0]=0;
            queue<int>que;
            for(int i=0; i<26; i++) {
                int u=ch[0][i];
                if(u) {
                    fail[u]=0;
                    que.push(u);
                }
            }
            while(!que.empty()) {
                int u=que.front(); 
                que.pop();
                for(int i=0; i<26; i++) {
                    int v=ch[u][i];
                    if(!v) {
                        ch[u][i]=ch[fail[u]][i];
                        continue;
                    }
                    que.push(v);
                    int k=fail[u];
                    fail[v]=ch[k][i];
                    last[v]=val[fail[v]] ? fail[v] : last[fail[v]];
                }
            }
        }
        void work(int x) {
            if(val[x]) {
                ans+=val[x];
                val[x]=0;
                work(last[x]);
            }
        }
        void find(char *s) {
            int len=strlen(s);
            int u=0;
            for(int i=0; i<len; i++) {
                int v=(s[i]-'a');
                if(!ch[u][v])u=fail[u];
                while(u&&!ch[u][v])
                    u=fail[u];
                u=ch[u][v];
                if(val[u])
                    work(u);
                else if(last[u])
                    work(last[u]);
            }   
        }       
    } ac;
    
    int main() {
    
        scanf("%d",&n);
        ac.init();
        for(int i=1; i<=n; i++) {
            scanf("%s",s);
            ac.insert(s);
        }
        ac.get_fail();
        scanf("%s",s);
        ac.find(s);
        printf("%d
    ",ans);
        return 0;
    }
    AC自动机

    虚树

    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    inline int read() { 
        int x = 0,f = 1; 
        char c = getchar(); 
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar(); } 
        while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar(); 
        return x * f; 
    } 
    const int maxn = 300007; 
    int n; 
    struct node { 
        int v,next; 
    } edge[maxn << 1],e[maxn << 1];   
    int head[maxn],num,h[maxn],num1,deep[maxn];  
    inline void add(int u,int v) { if(u == v) return; 
        e[++ num1].v = v;e[num1].next = h[u];h[u] = num1; 
    } 
    inline void add_edge(int u,int v ) { 
        edge[++ num].v = v;edge[num].next = head[u];head[u] = num; 
    } 
    
    int dfn[maxn],cnt = 0,dad[maxn][20],size[maxn]; 
    
    void dfs(int x,int fa) { 
        size[x] = 1; 
        dfn[x] = ++ cnt; deep[x] = deep[fa] + 1; dad[x][0] = fa; 
        for(int i = 0;dad[x][i];++ i) 
            dad[x][i + 1] = dad[dad[x][i]][i]; 
        for(int i = head[x];i;i = edge[i].next ) { 
             int v = edge[i].v; 
             if(v == fa) continue; 
             dfs(v,x); 
            size[x] += size[v]; 
        } 
    } 
    int lca(int x,int y) {
        if(deep[x] > deep[y]) std::swap(x,y); 
        for(int i = 18;i >= 0;-- i)if(deep[x] <= deep[dad[y][i]]) y = dad[y][i]; 
            if(x == y) return x; 
        for(int i = 18;i >= 0;-- i) if(dad[x][i] != dad[y][i])x = dad[x][i],y = dad[y][i];  
        return x == y ? x : dad[x][0]; 
    } 
    
    inline bool cmp(int x,int y) {return dfn[x] < dfn[y];} 
    int c[maxn],rem[maxn],Dfn,bel[maxn];  
    
    int dis(int x,int y) { 
        return deep[x] + deep[y] - 2 * deep[lca(x,y)]; 
    } 
    
    void get_fri(int x) { 
        c[++ Dfn] = x;rem[x] = size[x];  
        for(int i = h[x];i;i = e[i].next ) { 
            int v = e[i].v; 
            get_fri(v); 
            if(!bel[v]) continue; 
            int t1 = dis(bel[v],x),t2 = dis(bel[x],x); 
            if((t1 == t2 && bel[v] < bel[x]) || t1 < t2 || !bel[x]) bel[x] = bel[v]; 
        } 
    }   
    void get_sec(int x) { 
        for(int i = h[x];i;i = e[i].next) { 
            int v = e[i].v; 
            int t1 = dis(bel[x],v),t2 = dis(bel[v],v); 
            if((t1 == t2 && bel[v] > bel[x]) || t1 < t2 || !bel[v])bel[v] = bel[x]; 
            get_sec(v); 
        }       
    } 
    
    int dp[maxn]; 
    void divide(int a,int b) { 
        int x = b,mid = b; 
        for(int i = 18;i >= 0;-- i) 
            if(deep[dad[x][i]] > deep[a]) x = dad[x][i]; 
        rem[a] -= size[x]; 
        if(bel[a] == bel[b]) {
            dp[bel[a]] += size[x] - size[b]; return; 
        }  
        for(int i = 18;i >= 0;-- i) { 
            if(deep[dad[mid][i]] <= deep[a]) continue; 
            int t1 = dis(bel[a],dad[mid][i]),t2 = dis(bel[b],dad[mid][i]); 
            if(t1 > t2 || (t1 == t2 && bel[b] < bel[a]))mid = dad[mid][i]; 
        } 
        dp[bel[a]] += size[x] - size[mid]; 
        dp[bel[b]] += size[mid] - size[b]; 
    } 
    int htmp[maxn],stack[maxn],H[maxn]; 
    void solve(int k = 0) { 
        int top;memset(h,0,sizeof h);
        top = Dfn = 0;
        k = read(); 
        for(int i = 1;i <= k;++ i) htmp[i] = H[i] = read(); 
        for(int i = 1;i <= k;++ i) bel[H[i]] = H[i] ; 
        std::sort(H + 1,H + k + 1,cmp); 
        stack[++ top] = 1; 
        for(int i = 1;i <= k;++ i) { 
            int x = H[i],f = lca(stack[top],x); 
            while("tle") { 
                if(deep[f] >= deep[stack[top - 1]]) { 
                    add(f,stack[top --]); 
                    if(stack[top] != f) stack[++ top] = f; 
                    break;  
                }  add(stack[top - 1],stack[top]);top --;  
            }  if(stack[top] != x) stack[++ top] = x;   
        } 
        while(top - 1) add(stack[top - 1],stack[top]),top --; 
        get_fri(1); 
        get_sec(1); 
        for(int i = 1;i <= Dfn;++ i)  
            for(int j = h[c[i]];j;j = e[j].next) { 
                    divide(c[i],e[j].v);        
            } 
        for(int i = 1;i <= Dfn;++ i) dp[bel[c[i]]] += rem[c[i]]; 
            for(int i = 1;i <= k;++ i) printf("%d ",dp[htmp[i]]);puts(""); 
        for(int i = 1;i <= Dfn;++ i) dp[c[i]] = bel[c[i]] = H[c[i]] = rem[c[i]] = 0; 
        num1 = 0; 
    } 
    int main() { 
        n = read(); 
        for(int u,v,i = 1;i < n;++ i) { 
            u = read(),v = read(); 
            add_edge(u,v);add_edge(v,u); 
        } 
        dfs(1,0);   
        int q = read() ; 
        for(;q --;)  
        solve(); 
        return 0; 
    } 
     
    虚数

    排序

    快排+求k大值

    int qsort(int *a,int l,int r)
    {
        int tmp = a[l],pos = l;
        int i = l, j = r;
        while (i<j)
        {
            while (i<j&&a[j]>tmp) j--;
            if (i<j)
            {
                a[pos] = a[j];
                pos = j;
            }
            while (i<j&&a[i]<tmp) i++;
            if (i<j)
            {
                a[pos] = a[i];
                pos = i;
            }
        }
        a[pos] = tmp;
        return pos;
    }
    int findkth(int *a,int n,int k)
    {
        int l = 0,r = n-1;
        while (1)
        {
            int pos = qsort(a,l,r);
            if (pos==n-k) return a[pos];
            else if (pos<n-k) l = pos+1;
            else r = pos-1;
        }
    }
    
    快速排序求第k大的数
    q_sort

    归并+求逆序对

    #include<cstdio>
    
    int n,ans;
    int a[500100],b[500100];    //a原数组,b暂存数组 
    
    void merge_sort(int l,int r)    //归并 
    {
        if (l==r) return ;    //一个数不用排序 
        int m = (l+r)>>1;
        merge_sort(l,m);    //排序左边 
        merge_sort(m+1,r);    //排序右边 
        int i = l, j = m+1, k = l ;    //i左边最小的位置,j右边最小的位置 
        while (i<=m && j<=r)
            if (a[i]<=a[j]) b[k++] = a[i++];
            else ans += m-i+1, b[k++] = a[j++];    //加入右半段时,逆序对数增加 
        while (i<=m) b[k++] = a[i++];    //加入左边剩余的数 
        while (j<=r) b[k++] = a[j++];    //加入右边剩余的数
        for (i=l; i<=r; ++i) a[i] = b[i];    //从暂存数组中赋值 
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1; i<=n; ++i)
            scanf("%d",&a[i]);
        merge_sort(1,n);
        printf("%d",ans);
        return 0;
    }
    m_sort

    数学

    组合数递推

    C[1][0] = C[1][1] = 1;
    for (int i=2; i<=N; i++)
    {
        C[i][0] = 1;
        for (int j=1; j<=N; j++)
            C[i][j] = C[i-1][j]+C[i-1][j-1];
    }
    组合数递推公式

    线性筛求莫比乌斯函数(mu)

    void get()
    {
        int n = 100;
        mu[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(!ol[i])prime[++num]=i,cout<<i<<" ",mu[i]=-1;
            for(int j=1;j<=num&&j*prime[i]<=n;j++)
            {
                ol[i*prime[j]]=1;
                if((i%prime[j])==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
        cout<<num<<endl;
    }
    莫比乌斯

     根n求欧拉函数

    int getphi(int x){
        int ret=1;
        for(int i=1;prime[i]*prime[i]<=x;i++){
            if(x%prime[i]==0)
            {
                ret*=prime[i]-1;
                x/=prime[i];
                while(x%prime[i]==0)
                x/=prime[i],ret*=prime[i];
            }
        }
        if(x>1) ret*=x-1;
        return ret;
    }
    求欧拉

    矩阵乘法(fib

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int mod = 1e9+7;
    const int N = 2;
    
    struct Matrix{
        int a[N][N];
        Matrix(){
            this->clear();
        }
        void clear(){
            memset(a,0,sizeof(a));
        }
        void setone(){
            this->clear();
            for (int i=0; i<N; ++i)
                a[i][i] = 1;
        }
        Matrix operator * (const Matrix &x) const 
        {
            Matrix c;
            for (int k=0; k<N; k++)
                for (int i=0; i<N; ++i)
                    for (int j=0; j<N; ++j)
                        c.a[i][j] = (c.a[i][j]+1ll*a[i][k]*x.a[k][j])%mod;
            return c;
        }
    };
    
    int fibn(int n)
    {
        Matrix x,s;
        x.a[0][0] = x.a[0][1] = x.a[1][0] = 1;
        s.setone();
        for (; n; n>>=1)
        {
            if (n&1) s = s*x;
            x = x*x; 
        }
        return (s.a[0][0]+s.a[0][1])%mod;
    }
    int main()
    {
        int n;
        while (~scanf("%d",&n))
        {
            if (n==1||n==2) puts("1");
            else printf("%d
    ",fibn(n-2));
        }
        return 0;
    }
    矩阵乘法快速幂求斐波那契

    逆元相关:

    线性求逆元

    #include<cstdio>
    #include<algorithm>
    #define LL long long
    LL inv[3000053];
    //int inv[MAXN]; 
    void INV(int a,int p) 
    {
        inv[1] = 1;
        for (int i=2; i<=a; ++i)
            inv[i] = (LL)((p-(p/i)%p)%p*inv[p%i])%p; 
    }
    
    
    int main() {
        int n,p;
        scanf("%d%d",&n,&p);
        INV(n,p);
        for(int i=1;i<=n;++i) 
            printf("%d
    ",inv[i]);
        return 0;
    }
    线性求逆元
    #include<cstdio>
    #include<algorithm>
    #define LL long long
    LL inv[3000053];
    //int inv[MAXN]; 
    void INV(int a,int p) 
    {
        inv[1] = 1;
        for (int i=2; i<=a; ++i)
            inv[i] = (LL)((p-(p/i)%p)%p*inv[p%i])%p; 
    }
    
    
    int main() {
        int n,p;
        scanf("%d%d",&n,&p);
        INV(n,p);
        for(int i=1;i<=n;++i) 
            printf("%d
    ",inv[i]);
        return 0;
    }
    线性求逆元

     高斯消元

    void gauss() {
        int t;
        for(int i=1;i<=n;++i) {
            t=i;
            for(int j=i+1;j<=n;++j) if(loc[j][i]>loc[t][i]) t=j;
            if(t!=i) for(int j=i;j<=n+1;++j) std::swap(loc[t][j],loc[i][j]);
            for(int j=i+1;j<=n;++j) {
                double tmp=loc[i][i]/loc[j][i];
                for(int k=i+1;k<=n+1;++k) loc[j][k]=loc[i][k]-tmp*loc[j][k];
            }
        }
        for(int i=n;i>=1;--i) { 
            for(int j=i+1;j<=n;++j) loc[i][n+1]-=x[j]*loc[i][j];
            x[i]=loc[i][n+1]/loc[i][i];
        }
    }
    guass消元

    扩展欧几里得求逆元

    #include<cstdio>
    
    int exgcd(int a,int b,int &x,int &y)
    {
        if (b==0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int r = exgcd(b,a%b,x,y);
        int tmp = x;
        x = y;
        y = tmp-a/b*y;
        return r;
    }
    
    int main()
    {
        //gcd(a,p)==1
        int a,p,r,x,y;
        while (scanf("%d%d",&a,&p)!=EOF)
        {
            r = exgcd(a,p,x,y);
            printf("%d",(x%p+p)%p);
        }
        return 0;
    }
    扩展欧几里得求逆元

    数论bsgs+exgcd+q_pow

    1 #include<cstdio>
      2 #include<map>
      3 #include<cmath>
      4 using namespace std;
      5 
      6 typedef long long LL;
      7 int T,L;
      8 
      9 LL qpow(LL a,LL p,LL mod)
     10 {
     11     LL base=a;
     12     LL sum=1;
     13     while(p!=0)
     14     {
     15         if(p&1)
     16         sum=(sum*base)%mod;
     17         base=(base*base)%mod;
     18         p>>=1;
     19     }
     20     return sum;
     21 }
     22 
     23 void work1()
     24 {
     25     LL y,z,p;
     26     scanf("%lld%lld%lld",&y,&z,&p);
     27     printf("%lld
    ",qpow(y,z,p)%p);
     28     return ;
     29 }
     30 
     31 
     32 void exgcd(int a,int b,LL &d,LL &x,LL &y)
     33 {
     34     if(!b){d=a;x=1;y=0;return ;}
     35     exgcd(b,a%b,d,y,x);
     36     y-=x*(a/b);
     37 }
     38 LL gcd(LL a,LL b)
     39 {
     40     if(!b) return a;
     41     return gcd(b,a%b);
     42 }
     43 void work2()
     44 {
     45     LL a,b,y,z,x,d,mod;
     46     scanf("%lld%lld%lld",&y,&z,&mod);
     47     a=y;
     48     b=-mod;
     49     d=gcd(a,b);
     50     if(z%d)
     51     {
     52         printf("Orz, I cannot find x!
    ");
     53         return ;
     54     }
     55     a/=d;b/=d;z/=d;
     56     exgcd(a,b,d,x,y);
     57     x*=z;x%=b;
     58     while(x<0)    x+=b;
     59     printf("%lld
    ",x);
     60 }
     61 
     62 
     63 map<LL,LL>mp;
     64 void work3()
     65 {
     66     mp.clear();
     67     LL y,z,q,p;
     68     scanf("%lld%lld%lld",&y,&z,&p);
     69     y%=p;
     70     if(!y&&!z)
     71     {
     72         puts("1");return ;
     73     }
     74     if(!y)
     75     {
     76         printf("Orz, I cannot find x!
    ");
     77         return;
     78     }
     79     LL pos=ceil(sqrt(p));
     80     LL ans;
     81     for(LL i=0;i<=pos;i++)
     82     {
     83         if(i==0)
     84         {
     85             ans=z%p;
     86             mp[ans]=1;
     87             continue;
     88         }
     89         ans=(ans*y)%p;
     90         mp[ans]=i;
     91     }
     92     ans=1;
     93     LL t=qpow(y,pos,p);
     94     for(LL i=1;i<=pos;i++)
     95     {
     96         ans=(ans*t)%p;
     97         if(mp[ans])
     98         {
     99             LL b=i*pos-mp[ans];
    100             printf("%d
    ",(b%p+p)%p);
    101             return ;
    102         }
    103     }
    104     printf("Orz, I cannot find x!
    ");
    105 }
    106 int main()
    107 {
    108     scanf("%d%d",&T,&L);
    109     if(L==1)
    110     for(int i=1;i<=T;i++)
    111     work1();
    112     if(L==2)
    113     for(int i=1;i<=T;i++)
    114     work2();
    115     if(L==3)
    116     for(int i=1;i<=T;i++)
    117     work3();
    118     return 0;
    119 }
    bsgs

    同于方程组:

    中国剩余定理

    /*long long gcd(LL a,LL b)
    {
        return b==0?a:gcd(b,a%b);
    }*/
    #include<cstdio>
    #define ll long long
    //扩展欧几里得算法 
    void gcd(ll a,ll b,ll &d,ll &x,ll &y)
    {
        if(b==0){
            d=a;
            x=1,y=0;
        }
        else{//else不能省略 
            gcd(b,a%b,d,y,x);
            y-=(a/b)*x;
        }
    }
    //中国剩余定理 
    ll China(int n,ll *m,ll *a)
    {
        ll M=1,d,y,x=0;
        for(int i=0;i<n;i++) M*=m[i];
        for(int i=0;i<n;i++){
            ll w=M/m[i];
            gcd(m[i],w,d,d,y);
            x=(x+y*w*a[i])%M;
        }
        return (x+M)%M;
    }
    ll m[15],a[15];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%lld%lld",&m[i],&a[i]);
        printf("%lld",China(n,m,a));
    }
    crt

    扩展欧几里得解法

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    #define LL long long
    LL a[6],r[6];
    int n;
    
    LL exgcd(LL a,LL b,LL &x,LL &y) {
        if(b==0) {x=1,y=0;return a;}
        LL tmp=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return tmp;
    }
    LL solve() {
        LL M=a[1],R=r[1],x,y,d;
        for(int i=2;i<=4;i++) {
            d=exgcd(M,a[i],x,y);
            if((R-r[i])%d!=0) return -1;
            x=(R-r[i])/d*x%a[i];
            R-=x*M;
            M=M/d*a[i];
            R%=M;
        }
        return (R%M+M)%M;
    }
    
    int main() {
        for(int i=1; i<=4; i++)
        scanf("%lld%lld",&a[i],&r[i]);
        printf("%lld
    ",solve());
        return 0;
    }
    exgcd

     矩阵快速幂

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    int n;LL k;
    const int mod = 1e9+7;
    struct Matrix {
        LL a[107][107];
        Matrix() {
            std::memset(a,0,sizeof a);
        }
        Matrix operator * (const Matrix & y)const   {
            Matrix ans;
            for(int i=1;i<=n;++i) {
                for(int j=1;j<=n;++j) {
                    for(int k=1;k<=n;++k) {
                        ans.a[i][j]=(ans.a[i][j]+((a[i][k]%mod)*(y.a[k][j]%mod)))%mod;
                    }
                }
            }
            return ans;
        }
            
    }pre,ans;
    void pow(LL k) {
        for(int i=1;i<=n;++i) 
            ans.a[i][i]=1;
        while(k) {
            if(k&1) ans=ans*pre;
            pre=pre*pre;
            k>>=1;
        }
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=n;++j) {
                printf("%lld ",ans.a[i][j]);
            }
            puts("");
        }
        return ;
    }
    int main() {
        scanf("%d%lld",&n,&k);
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=n;++j) {
                scanf("%d",&pre.a[i][j]);
            }
        }
        pow(k);
        return 0;
    }
    矩阵快速幂

     高消异或

    #include<bits/stdc++.h> 
    using namespace std; // 每天好心情从namespace开始 
    const int maxn = 157; 
    #define LL long long 
    inline LL read() { 
        LL x = 0,f = 1;
        char c = getchar(); 
        while(c < '0' || c > '9'){if(c == '-')f = - 1;  c = getchar();}  
        while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
        return x * f; 
    } 
    int n; 
    const int mod = 1000000007; 
    long long A[100007]; 
    int prime[100007],is[100007],num = -1; 
    void getprime() { 
        for(int i = 2;i <= 2000;++ i) { 
            if(!is[i]) prime[++ num] = i;  
            for(int j = 0;j <= num && prime[j] * i <= 2000;++ j) { 
                is[i * prime[j]] = 1; 
                if(i % prime[j] == 0) break; 
            } 
        } 
    } 
    bitset<330>a[305]; 
    int guass(int equ,int var) { 
        int r,c,t,j = 0; 
        for(r = c = 0;r < equ && c < var;++ r, ++c) { 
            for(t = r;t < equ;++ t) if(a[t][c]) break; 
            if(t == equ) { 
                 r --;continue; 
            } else swap(a[t],a[r]); 
            for(int i = r + 1; i < equ;++ i) if(a[i][c]) a[i] ^= a[r]; 
        } 
        return var - r; 
    } 
    int solve() { 
        for(int i = 0; i < 305; i++) a[i].reset(); 
        for(int i = 0;i < n;++ i)  
            for(int j = 0;j <= num;++ j) { 
                LL tmp = A[i]; 
                if(tmp % prime[j] == 0) { 
                    bool flag = 0; 
                    while(tmp % prime[j] == 0) { 
                        tmp /= prime[j]; 
                        flag ^= 1; 
                    } 
                    a[j][i] = flag; 
                } 
            } 
        int zyy = guass(num + 1,n); 
        LL ret = 1; 
        for(int i = 1;i <= zyy;++ i)ret <<= 1,ret %= mod; 
        return ret - 1; 
    } 
    int main() { 
        getprime(); 
        int t = read(); 
        int cas = 0;  
        while(t --) { 
            ++ cas; 
            printf("Case #%d:
    ",cas); 
            n = read(); 
            for(int i = 0;i < n;++ i) A[i] = read();  
            printf("%d
    ",solve()); 
        } 
        return 0; 
    } 
    高消异或

    反演

    #include <queue> 
    #include <cstdio> 
    #include <algorithm> 
    inline int read() { 
        int x = 0; 
        char c = getchar(); 
        while(c < '0' || c > '9')c = getchar();  
        while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
        return x; 
    } 
    const int mod = (1 << 31); 
    const int maxn = 100007; 
    int p[maxn],mu[maxn],mx; bool vis[maxn]; 
    struct node { 
        int n,m,a,id; 
        bool operator < (const node & k)const { 
            return a < k.a; 
        } 
    } q[maxn]; 
    std::pair<int,int>F[maxn]; 
    void getmu() { 
        int size = mx,num = 0; 
        mu[1] = 1; 
        for(int i = 2;i <= size;++ i) { 
            if(!vis[i]) p[++ num] = i,mu[i] = -1; 
            for(int j = 1;j <= num && i * p[j] <= size;++ j) {  
                vis[i * p[j]] = true; 
                if(i % p[j] == 0) { 
                    mu[i * p[j]] = 0; break; 
                } mu[i * p[j]] = -mu[i];  
            } 
        } 
        for(int i = 1;i <= size;++ i) 
            for(int j = i;j <= size;j += i) 
                F[j].first += i; 
        for(int i = 1;i <= size;++ i)F[i].second = i; 
    } 
    int ans[maxn]; 
    #define lowbit(x) x&(-x)
    int bit[maxn << 1]; 
    void add(int x,int num) { 
        for(int i = x;i <= mx; i += lowbit(i))bit[i] += num; 
    } 
    int query(int x) { 
        int ret = 0; 
        for(int i = x;i; i -= lowbit(i)) ret += bit[i]; 
        return ret; 
    } 
    void solve(int x) { 
        int n = q[x].n,m = q[x].m; 
        for(int i = 1,j;i <= q[x].n;i = j + 1) { 
            j = std::min(m / (m / i),n / (n/i)); 
            ans[q[x].id] += (n / i) * (m / i) * (query(j) - query(i - 1)); 
        } 
    } 
    int main() { 
        int k = read(); 
        for(int i = 1;i <= k;++ i) { 
            q[i].n = read(),q[i].m = read(),q[i].a = read(); 
            if(q[i].n > q[i].m) std::swap(q[i].n,q[i].m); 
            q[i].id = i; mx = std::max(mx,q[i].n); 
        } 
        getmu(); 
        std::sort(q + 1,q + k + 1); 
        std::sort(F + 1,F + mx + 1); 
        for(int i = 1,now = 0;i <= k;++ i) { 
            for(;now + 1 <= mx && F[now + 1].first <= q[i].a;) { 
                now ++; 
                for(int j = F[now].second;j <= mx;j += F[now].second) { 
                    //printf("%d
    ",now); 
                    add(j,F[now].first * mu[j / F[now].second]); 
                } 
            } 
            solve(i); 
        } 
        //printf("%d
    ",mod); 
        for(int i = 1;i <= k;++ i) { 
            printf("%d
    ",ans[i] & 0x7fffffff ); 
        } 
        return 0; 
    }
    反演

    杂七杂八算法

    二分查找+lower_bound(有序序列

    int binary_search(int x,int y,int c)
    {
        int l,r,mid;
        l = x; 
        r = y;
        while (l<r)
        {
            mid = (l+r)>>1;
            if (c<=a[mid]) r = mid;
            else l = mid+1;
        }
        return l;
    }
    /*------------------------------------*/
    int find(int l,int r,int x)
    {
        while (l<=r)
        {
            int mid = (l+r)>>1;
            if (a[mid]<=x) l = mid+1;
            else r = mid-1;
        }
        return l;
    }
    二分查找

    lower_bound

     lower_bound(a+x,a+y+1,c)-a; 
    lower_bound

    莫队

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N = 100010;
    int n,m,num,a[N];
    struct data{
        int l,r,id,block;
    }q[N];
    int cnt[N],ans[N];
    
    bool cmp(data a,data b)
    {
        if(a.block==b.block) return a.r<b.r;
        return a.block < b.block;
    }
    int tmp;
    /*void add(int x)
    {
        cnt[a[x]]++;
        if(cnt[a[x]]==1)tmp++;
    }
    void del(int x)
    {
        cnt[a[x]]--;
        if(!cnt[a[x]])tmp--;
    }*/
    void Solve()
    {
        int l=1,r=0;
        for(int i=1;i<=m;i++)
        {
            while(l<q[i].l) del(l),l++;
            while(l>q[i].l) l--,add(l);
            while(r<q[i].r) r++,add(r);
            while(r>q[i].r) del(r),r--;
            ans[q[i].id]=tmp;
        }
    }
    int main()
    {
        cin>>n;
        num=sqrt(n);
        for(int i=1;i<=n;i++)cin>>a[i];
        cin>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>q[i].l>>q[i].r;
            q[i].id=i;
            q[i].block=(q[i].l-1)/num+1;
        }
        sort(q+1,q+m+1,cmp);
        Solve();
        for(int i=1;i<=m;i++)
            printf("%d
    ",ans[i]);
        return 0;    
    }
    莫队

    分块的构造??(假的

    inline void divide(int x)
    {
        for(int i=1;i<=x;i++)
        left[i]=right[i-1]+1,right[i]=i*x;
        right[x]=n;
        for(int i=1;i<=x;i++)
            for(int j=left[i];j<=right[i];j++)
            belong[j]=i;
        for(int i=n;i>=1;i--)
        {
            if(where[i]>right[belong[i]])out[i]=1;
            else out[i]=out[where[i]]+1,where[i]=where[where[i]];
        }
    }
    
    inline void query(int x)
    {
        int ans=0;
        while(x<=n)
        {
            ans+=out[x],x=where[x];
        }
        printf("%d
    ",ans);
    }
    
    inline void modify(int x,int y)
    {
        int i,j;
        int tmp=belong[x],l=left[tmp],r=right[tmp];
        a[x]=x+y;
        if(a[x]>r)out[x]=1,where[x]=a[x];
        else out[x]=out[a[x]]+1,where[x]=where[a[x]];
        for(i=x-1;i>=l;i--)
        {
            if(a[i]<=x)
            out[i]=out[a[i]]+1,where[i]=where[a[i]];
        }
    }
    
        n=read();
        int x=sqrt(n);
        for(int i=1;i<=n;i++)
        a[i]=read(),where[i]=i+a[i],a[i]=where[i];
    分块

     点分治

     #include<cstdio> 
    #include<algorithm> 
    inline int read() { 
        int x = 0,f = 1;
        char c = getchar(); 
        while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 
        while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
        return x * f;   
    } 
    const int maxw = 2000007;
    const int maxn = 160000 + 10000 + 7;  
    struct Query {
        int x,y,type,w,aid; 
        Query(int Type = 0,int X = 0,int Y = 0,int W = 0,int Aid = 0) : type(Type),x(X),y(Y),w(W),aid(Aid){}; 
        bool operator < (const Query & A)const { 
            return x == A.x ? type < A.type : x < A.x; 
        }
    } ;
    Query query[maxw / 10 + 7];
    Query tmp[maxw / 10 + 7]; 
    int ans[maxn],maxy;  
    namespace BIT {
    #define lowbit(x) (x & (-x))
        int sum[maxw << 1]; 
        void add(int idx,int val) { 
        //puts("1");
            for(;idx <= maxy; idx += lowbit(idx)) sum[idx] += val; 
        } 
        int query(int idx) { 
            int ret = 0; 
            for(;idx;idx -= lowbit(idx)) ret += sum[idx]; 
            return ret;  
        } 
        void clear(int idx) { 
            for(;idx <= maxy;idx += lowbit(idx)) { 
                if(sum[idx]) sum[idx] = 0; 
                else break; 
            } 
        } 
    } 
    void cdq(int l,int r) { 
        if(r - l <= 1) return; 
        int mid = l + r >> 1; 
        cdq(l,mid);cdq(mid,r); 
        int p = l,q = mid,cnt = l; 
        for(;p < mid && q < r;) {
            if(query[p] < query[q]) {
                if(query[p].type == 1) 
                    BIT::add(query[p].y,query[p].w); 
                tmp[cnt ++] = query[p ++]; 
            }
            else { 
                if(query[q].type == 2) ans[query[q].aid] += query[q].w * BIT::query(query[q].y); 
                tmp[cnt ++] = query[q ++];  
            } 
        } 
        while(p < mid) tmp[cnt ++] = query[p ++]; 
        while(q < r)  {
            if(query[q].type == 2) ans[query[q].aid] += query[q].w * BIT::query(query[q].y); 
                tmp[cnt ++] = query[q ++]; 
        } 
        for(int i = l;i < r;++ i) { 
            BIT::clear(tmp[i].y); 
            query[i] = tmp[i];  
        } 
    } 
    int qid = 0,aid = 0;
    int main() { 
        int type = read(), n = read(); 
        maxy = n; 
        for(int x,y,x1,y1,val;;) { 
            type = read(); 
            if(type == 3) break;  
            if(type == 1) {x = read(),y = read(),val = read();query[qid ++] = Query(1,x,y,val,0);  } 
            if(type == 2) { 
                x = read(),y = read(),x1 = read(),y1 = read(); 
                query[qid ++] = Query(2,x - 1,y - 1,1,aid); 
                query[qid ++] = Query(2,x - 1,y1,-1,aid); 
                query[qid ++] = Query(2,x1,y - 1,-1,aid); 
                query[qid ++] = Query(2,x1,y1,1,aid); 
                aid ++; 
            } 
        } 
        cdq(0,qid); 
        for(int i = 0;i < aid;++ i) printf("%d
    ",ans[i]); 
        return 0; 
    } 
    点分治

    模拟退火

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int maxn = 100007;
    double x[maxn],y[maxn],w[maxn]; 
    int n;double ansx,ansy,nowx,nowy,Ans = 1.0 * 1e18;
    double calc(double X,double Y) {
        double ret = 0; 
        for(int i = 1;i <= n;++ i) 
            ret += w[i] * sqrt((X - x[i]) * (X - x[i]) + (Y - y[i]) * (Y - y[i]));
        if(ret < Ans) Ans = ret,ansx = X,ansy = Y;
        return ret;
    }
    double Random() {return (double) rand() / RAND_MAX;} 
    void SA(double T) {
        nowx = ansx,nowy = ansy;
        double tmpx ,tmpy;
        while(T > 0.001) {
            tmpx = nowx + T * (Random() * 2 - 1);
            tmpy = nowy + T * (Random() * 2 - 1); 
            double DE = calc(nowx,nowy) - calc(tmpx,tmpy); 
            if(DE > 0 || Random() <= exp(DE/T)) 
                nowx = tmpx,nowy = tmpy;
            T *= 0.98;
        } 
         
        for(int i = 1;i <= 1000;++ i) {
            tmpx = ansx + T * (Random() * 2 - 1) ; 
            tmpy = ansy + T * (Random() * 2 - 1) ; 
            calc(tmpx,tmpy); 
        } 
    }
    int main() {
        srand(19260817); 
        scanf("%d",&n);
        for(int i = 1;i <= n;++ i) scanf("%lf%lf%lf",x + i,y + i,w + i),
            ansx += x[i],ansy += y[i]; 
        ansx /= n;ansy /= n;  
        //printf("%lf %lf
    ",Ans,ansy);
        SA(40000001); 
        printf("%.3lf %.3lf",ansx,ansy); 
        return 0; 
    }
    模拟退火

    图论相关

    lca相关

    链剖求lca

    #include <cstdio>
    #include <cstdlib>
    #define maxm 200010
    struct edge{int to,len,next;}E[maxm];
    int cnt,last[maxm],fa[maxm],top[maxm],deep[maxm],siz[maxm],son[maxm],val[maxm];
    void addedge(int a,int b,int len=0)
    {
        E[++cnt]=(edge){b,len,last[a]},last[a]=cnt;
    }
    void dfs1(int x)
    {
        deep[x]=deep[fa[x]]+1;siz[x]=1;
        for(int i=last[x];i;i=E[i].next)
        {
            int to=E[i].to;
            if(fa[x]!=to&&!fa[to]){
                val[to]=E[i].len;
                fa[to]=x;
                dfs1(to);
                siz[x]+=siz[to];
                if(siz[son[x]]<siz[to])son[x]=to;
            }
        }
    }
    void dfs2(int x)
    {
        if(x==son[fa[x]])top[x]=top[fa[x]];
        else top[x]=x;
        for(int i=last[x];i;i=E[i].next)if(fa[E[i].to]==x)dfs2(E[i].to);
    }
    void init(int root){dfs1(root),dfs2(root);}
    int query(int x,int y)
    {
        for(;top[x]!=top[y];deep[top[x]]>deep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
        return deep[x]<deep[y]?x:y;
    }
    int n,m,x,y,v;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);addedge(x,y,v);addedge(y,x,v);
        }
        init(1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            printf("%d
    ",query(x,y));
        }
        return 0 ;
    }
    链剖lca

    倍增lca

    //lca   倍增 
     2 /*倍增法
     3 
     4 首先如果两个点的深度如果不同,
     5 将深度较大的点跳到与深度较小的点一样的深度,
     6 再同时向上跳,首次相遇时即为最近公共祖先。
     7 */
     #include<cstdio>
     
     using namespace std;
     
     const int N=10015;
     
     vector<int>vec[N];
     int n,m,t,p,q;
     
     int dad[N][N],deep[N];
     
     void dfs(int x)
     {
         deep[x]=deep[dad[x][0]]+1;
         for(int i=0;dad[x][i];i++)
       {
             dad[x][i+1]=dad[dad[x][i]][i];//滚动赋值,如果存在节点x的第2^i的祖先那么节点x的第2^(i+1)个祖先=节点x的2^i的祖先再往前走2^i个祖先
         }
         for(int i=0;i<vec[x].size();i++)
         if(!deep[vec[x][i]])
         {
             dad[vec[x][i]][0]=x;
             dfs(vec[x][i]);
         }
     }
     
     int lca(int x,int y)
     {
         if(deep[x]>deep[y])swap(x,y);
         for(int i=20;i>=0;i--)
         {
             if(deep[dad[y][i]]>=deep[x])y=dad[y][i];
         }//自己跳 
         if(x==y)return x;
         
         for(int i=20;i>=0;i--)
         if(deep[dad[x][i]]!=deep[dad[y][i]])
         {
             x=dad[x][i];
             y=dad[y][i];
         }//一起跳 
         return dad[x][0]; 
     }
     
     int main()
     {
         scanf("%d%d%d",&n,&m,&t);//n个点,m条边,t个访问
         int x,y;
         
         for(int i=1;i<=m;i++)
         {
          scanf("%d%d",&x,&y);
             vec[x].push_back(y);
             vec[y].push_back(y);
         }
         dfs(1);
         while(t--)
         {
             scanf("%d%d",&p,&q);
             printf("%d
    ",lca(p,q));
         }
    }
    倍增lca

    tarjan+缩点

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    int n,m,topp;
    #define N 100006
    struct sta{
        int sz[100001];
        int top(){return sz[topp];}
        void push(int x){sz[++topp]=x;}
        void pop(){if(topp>0)topp--;}
    }stack;
    
    struct node{
        int v,next;
    }edge[N*5];int head[N],num;
    int dfn[N],low[N],color[N];bool vis[N];
    
    void add_edge(int x,int y)
    {
        edge[++num].v=y;edge[num].next=head[x];head[x]=num;
    }
    int cnt;
    void tarjan(int x)
    {
        dfn[x]=low[x]=++num;
        stack.push(x);
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].next)
        {
            int v=edge[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[x]=min(low[x],low[v]);
            }
            else if(vis[v])low[x]=min(low[x],dfn[v]);    
        }
        if(dfn[x]==low[x])
        {
            ++cnt;
            int r;
            do{
                r=stack.top();
                color[r]=cnt;
                vis[r]=0;
                stack.pop();
            }while(r!=x);
        }
        return ;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int a,b;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);add_edge(a,b);
        }
        num=0;
        for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++)
        {
            for(int j=head[i];j;j=edge[j].next)
            {
                int v=edge[j].v;
                if(color[i]!=color[v])
                {
                    vis[color[v]]=1;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=cnt;i++)
            if(!vis[i]) ans++;
        printf("%d
    ",ans);
        return 0;
    }
    tarjan+缩点

    树剖

    #include<bits/stdc++.h>
    using namespace std; 
    inline int read() { 
        int x = 0,f = 1; 
        char c = getchar(); 
        while(c < '0' ||c > '9'){if(c == '-')f= -1; c = getchar();} 
        while(c <= '9' &&c >= '0')x = x * 10 + c- '0',c = getchar(); 
        return x * f; 
    } 
    #define int long long
    const int maxn = 200007; 
    int n,m,val[maxn]; 
    struct node { 
        int u,v,next;
    } edge[maxn << 1]; 
    int head[maxn],num; 
    inline void add_edge(int u,int v) { 
        edge[++ num].v = v; edge[num].next = head[u];head[u] = num ; 
    } 
    int fa[maxn],deep[maxn],siz[maxn],son[maxn]; 
    void dfs1(int x) { 
        deep[x] = deep[fa[x]] + 1;siz[x] = 1;  
        for(int i = head[x];i ;i = edge[i].next) { 
            int v = edge[i].v; 
            if(deep[v]) continue; 
            fa[v] = x; dfs1(v); 
            siz[x] += siz[v]; 
            if(siz[v] > siz[son[x]] || !son[x]) son[x] = v; 
        } 
    }    
    int pos[maxn],_pos,sop[maxn],top[maxn]; 
    void dfs2(int x,int topfa) { 
        top[x] = topfa;pos[x] = ++_pos;sop[_pos] = x; 
        if(!son[x]) return ;
        dfs2(son[x],topfa); 
        for(int i = head[x];i;i = edge[i].next) { 
            int v = edge[i].v; 
            if(v == son[x] || v == fa[x]) continue; 
            dfs2(v,v); 
        } 
    } 
    #define lc rt << 1 
    #define rc rt << 1 | 1 
    int sum[maxn << 2],tag[maxn << 2]; 
    inline void update(int rt) {sum[rt] = sum[lc] + sum[rc]; } 
    void build(int rt,int l,int r) { 
        if(l == r) { 
            sum[rt] = val[sop[l]];return ;  
        } 
        int mid = l + r >> 1; 
        build(lc,l,mid); build(rc,mid + 1,r); 
        return update(rt); 
    } 
    inline void pushdown(int rt,int l,int r) { 
        int mid = l + r >> 1; 
        tag[lc] += tag[rt];tag[rc] += tag[rt]; 
        sum[lc] += (mid - l + 1) * tag[rt]; 
        sum[rc] += (r - mid) * tag[rt]; 
        tag[rt] = 0; 
    } 
    int T_query(int rt,int l,int r,int tl,int tr ){ 
        if(l >= tl && r <= tr) return sum[rt]; 
        if(tag[rt] != 0) pushdown(rt,l,r); 
        int mid = l + r >> 1,Ret = 0 ; 
        if(tl <= mid) Ret += T_query(lc,l,mid,tl,tr);  
        if(tr > mid)  Ret += T_query(rc,mid + 1,r,tl,tr); 
        return Ret;  
    } 
    void T_modify(int rt,int l,int r,int tl,int tr,int a) { 
        if(l >= tl && r <= tr) { 
            sum[rt] += (r - l + 1) * a; 
            tag[rt] += a; return ; 
        } 
        if(tag[rt] != 0)pushdown(rt,l,r); 
        int mid = l + r >> 1; 
        if(tl <= mid) T_modify(lc,l,mid,tl,tr,a); 
        if(tr > mid)  T_modify(rc,mid + 1,r,tl,tr,a); 
        update(rt); 
    } 
    int Q(int x) { 
        int ret = 0 ;
        for(;top[x] != 1;x = fa[top[x]]) 
            ret += T_query(1,1,n,pos[top[x]],pos[x]); 
        ret += T_query(1,1,n,pos[top[x]],pos[x]); 
        return ret; 
    } 
    void M1(int x,int a) { T_modify(1,1,n,pos[x],pos[x],a);  }  
    void M2(int x,int a) {  T_modify(1,1,n,pos[x],pos[x] + siz[x] - 1,a); }    
    main() { 
        n = read(),m = read(); 
        for(int i = 1;i <= n;++ i) val[i] = read(); 
        for(int u,v,i = 1;i < n;++ i) { 
            u = read(); v = read(); 
            add_edge(u,v); add_edge(v,u); 
        } 
        dfs1(1);  
        dfs2(1,1); 
        build(1,1,n); 
        for(int type,x,a;m --;) { 
            type = read(); 
            if(type == 1) { 
                x = read(); a = read(); 
                M1(x,a); 
            } else if(type == 2) { 
                x = read(); a = read(); 
                M2(x,a);    
            } else { 
                x = read(); 
                printf("%lld
    ",Q(x)) ;  
            } 
        } 
        return 0; 
    } 
    树剖

    割边

    void tarjan(int u,int fa) {
        dfn[u] = low[u] = ++tn;
        for (int i=head[u]; i; i=e[i].nxt) {
            int v = e[i].to;
            if (!dfn[v]) {
                tarjan(v,u);
                low[u] = min(low[u],low[v]);
                if (low[v] > dfn[u]) {
                    printf("%d %d
    ",u,v);
                }
            }
            else if (dfn[v] < dfn[u] && v != fa) 
                low[u] = min(low[u],dfn[v]);
        }
    }
    割边

    割点

    void tarjan(int u,int fa) {
        low[u] = dfn[u] = ++tn;
        int cnt_son = 0;
        for (int i=head[u]; i; i=e[i].nxt) {
            int v = e[i].to;
            if (!dfn[v]) {
                cnt_son++;
                tarjan(v,u);
                low[u] = min(low[u],low[v]);
                if (low[v] >= dfn[u]) 
                    iscut[u] = true;
            }
            else if (dfn[v] < dfn[u] && v != fa) 
                low[u] = min(low[u],dfn[v]);
        }
        if (fa<0 && cnt_son==1) iscut[u] = false;
    }
    割点
    边双连通分量
    写法1
    void tarjan(int u,int fa) {
        dfn[u] = low[u] = ++tn;
        st[++top] = u;
        vis[u] = true;
        for (int i=head[u]; i; i=e[i].nxt) {
            int v = e[i].to;
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }
            else if (vis[v] && v!=fa) 
                low[u] = min(low[u],dfn[v]);
        }
        if (dfn[u] == low[u]) {
            ++cnt;
            do {
                vis[st[top]] = false;
                bel[st[top]] = cnt;
                top--;
            } while (st[top+1] != u);
        }
    }
    边双联通分量写法1

    写法2

    void tarjan(int u,int fa) {
        dfn[u] = low[u] = ++tn;
        for (int i=head[u]; i; i=e[i].nxt) {
            int v = e[i].to;
            if (!dfn[v]) {
                tarjan(v,u);
                low[u] = min(low[u],low[v]);
            }
            else if (dfn[v] < dfn[u] && v != fa) 
                low[u] = min(low[u],dfn[v]);
        }
    }
    边双联通分量

    堆优化dijkstra

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define INF 0x3f3f3f3f
    #define N 1020
    
    int n,m;
    int head[N];
    int dis[N];
    
    struct nnode{
        int v;int w,next;
    }edge[N*N/2];
    struct node{
        int v,dis;
        friend bool operator < (node a,node b){
            return a.dis>b.dis;
        }
    }cur;
    priority_queue<node>q;
    
    int read() {
        int x=0,f=1;
        char c;
        while (c<'0' || c>'9') {if(c=='-')f = -1;c = getchar();}
        while (c>='0' && c<='9')x=x*10+c-'0',c=getchar();
        return x*f;
    }
    
    int num = 0;
    void add_edge(int x,int y,int w)
    {
        edge[num].v=y;
        edge[num].w=w;
        edge[num].next=head[x];
        head[x]=num++;
    }
    int pre_now[N];
    int pre[N];
    int Dijkstra(int p,int tp)
    {
        //memset (head,-1,sizeof -1);
        memset (dis,0x3f,sizeof dis);
        dis[1] = 0;
        q.push(node{1,0});
        while(!q.empty())
        {
            cur = q.top();
            q.pop();
            if(dis[cur.v]<cur.dis)continue;
            int u = cur.v;
            for (int i = head[u];i != -1;i = edge[i].next)
            {
                int v = edge[i].v;
                if((v == p && u== tp) || (v==tp && p == u))continue;
                if(dis[v]>dis[u]+edge[i].w)
                {
                    dis[v]=dis[u]+edge[i].w;
                    pre_now[v]=u;
                    q.push((node){v,dis[v]});
                }
            }
        }
        return dis[n];
    }
    
    int main() 
    {
        n = read();
        m = read();
        for(int i=1;i<=n;i++)head[i]=-1;    
        for (int i = 1; i <= m; i++){
            int a,b,c;
            a = read(),b = read(),c = read();
            add_edge(a,b,c);add_edge(b,a,c);
        }
        int ans=Dijkstra(0,0);
        memcpy(pre,pre_now,sizeof(pre));
        int k=n;
        while(k)
        {
            int tmp = Dijkstra(pre[k],k);
            if(tmp!=INF)
            ans = max(ans,tmp);
            k = pre[k];
        }
        
        printf("%d
    ",ans);
        return 0;
    }
    Dijkstra

    网络流相关

    最大流

    bool spfa() {
        memset(lev,-1,sizeof lev);
        memcpy(cur,head,sizeof head);
        queue<int>que;
        que.push(S);lev[S]=0;
        while(!que.empty()) {
            int u=que.front();que.pop();
            for(int i=head[u];i;i=edge[i].next) {
                int v=edge[i].v;
                if(edge[i].flow>0&&lev[v]<0) {
                    lev[v]=lev[u]+1;que.push(v);
                }
            }
        }
        if(lev[T]!=-1)return true;
        else return false;
    }   
    int dfs(int now,int flow) {
        if(now==T)return flow;
        int rest=0,delta;
        for(int &i=cur[now];i;i=edge[i].next) {
            int v=edge[i].v;
            if(lev[v]==lev[now]+1&&edge[i].flow>0) {
                delta=dfs(v,min(flow-rest,edge[i].flow));
                if(delta) {
                    edge[i].flow-=delta;
                    edge[i^1].flow+=delta;
                    rest+=delta;if(rest==flow)break;
                }
            }
        }
        if(rest==flow)lev[now]=-1;
        return rest;
    }
    int ans=0;
    void dinic() {
        while(spfa())
             ans-=dfs(S,INF);
    }
    Dinic

    最小费用最大流

    #include<queue>
    #include<cstdio>
    #include<cstring> 
    #include<algorithm>
    using namespace std;
    const int maxn = 4*50000;
    inline int read()
    {
        int x=0,f=1;char c= getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-'0');c=getchar();}
        return f*x;
    }
    struct node{
        int u,v,cost,flow,next;
    }edge[maxn];
    int head[maxn],num=1,n,m,s,t;
    int min_cost=0,max_flow=0;
    int dis[maxn],pre[maxn];
    bool vis[maxn];
    inline void add_edge(int x,int y,int z,int c)
    {    
        edge[++num].v=y;edge[num].u=x;edge[num].flow=z;edge[num].cost=c;edge[num].next=head[x];head[x]=num;
    }
    bool spfa()
    {
        memset(dis,0x3f,sizeof dis);
        memset(vis,0,sizeof vis);
        vis[s]=1;
        dis[s]=0;
        queue<int>que;
        que.push(s);
        while(!que.empty())
        {
            int u=que.front();
            que.pop();
            for(int i=head[u];i;i=edge[i].next)
            {
                int v=edge[i].v;
                if(dis[u]+edge[i].cost<dis[v]&&edge[i].flow>0)
                {
                    dis[v]=edge[i].cost+dis[u];
                    pre[v]=i;
                    if(!vis[v])
                    {
                        que.push(v);
                        vis[v]=1;
                    }
                }
            }
            vis[u]=0;
        }
        if(dis[t]==0x3f3f3f3f)return 0;
        else return 1;
    }
    void work()
    {
        int ma=0x3f3f3f3f;
        for(int i=t;i!=s;i=edge[pre[i]].u)
            ma=min(edge[pre[i]].flow,ma);
        for(int i=t;i!=s;i=edge[pre[i]].u)
        {
            edge[pre[i]].flow-=ma;
            edge[pre[i]^1].flow+=ma;
            min_cost+=(ma*edge[pre[i]].cost);
        }
        max_flow+=ma;
    }
    void miku()
    {
        while(spfa())
            work();
    }
    int main()
    {
        n=read(),m=read(),s=read(),t=read();
        int a,b,c,d;
        while(m--)
        {
            a=read(),b=read(),c=read(),d=read();
            add_edge(a,b,c,d);
            add_edge(b,a,0,-d);
        }
        miku();
        printf("%d %d
    ",max_flow,min_cost);
        return 0;
    }
    spfa费用流

    DP相关

    lcs

    #include<map>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    map<int,int>mp;
    inline int read()
    {
        int x=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar() ;
        return x;
    }
    int n,m,f[200010];
    int ef_search(int l,int r,int x)
    {
        while(l<r)
        {
            int mid=l+r>>1;
            if(x<=f[mid])r=mid;
            else l=mid+1;
        }
        return l;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
            mp[read()]=i;
        int len=0;
        for(int pos,i=1;i<=m;i++)
        {
            pos=mp[read()];
            if(!pos)continue;
            if(pos>f[len])f[++len]=pos;
            else {
                f[ef_search(1,len,pos)]=pos;
            }
        }
        printf("%d
    ",len);
        return 0;
     }
    lcs
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=505;
    int n,m,a[maxn],b[maxn];
    struct hehe {
        int num;
        vector<int>point;
    } dp[maxn],tmp,ans;
    
    int main() {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        for(int i=1;i<=n;i++) {
            tmp.num=0;
            tmp.point.clear();
            for(int j=1;j<=n;j++) {
                if (b[i]>a[j] && dp[j].num>tmp.num) tmp=dp[j];
                if (a[j]==b[i]) {
                    dp[j]=tmp;
                    dp[j].num=tmp.num+1;
                    dp[j].point.push_back(a[j]);
                }
            }
        }
        for(int i=1;i<=n;i++)
        if (dp[i].num>ans.num) ans=dp[i];
        printf("%d
    ",ans.num);
        for (int k=0; k<ans.point.size(); k++)
            printf("%d ",ans.point[k]);
        return 0;
    }
    上升公共

    上升

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int ans[100000];
    int a[100000];int len=1;
    inline int mid_serch(int x)
    {
        int l=0,r=len;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(ans[mid]<a[x])l=mid+1;
            else r=mid-1;
        }
        return l;
    } 
    int main()
    {
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;++i)scanf("%d",a+i);
        ans[1]=a[1];
        for(int i=2;i<=m;++i)
        {
            if(a[i]>ans[len])
            ans[++len]=a[i];
            else {
                int tmp=mid_serch(i);
                ans[tmp]=a[i];
            }
        }
        printf("%d",len);
    }
    上升

    多项式

    #include<cmath> 
    #include<cstdio>
    #include<cstring> 
    #include<algorithm> 
    
    inline int read() { 
        int x = 0; 
        char c = getchar(); 
        while(c < '0' || c > '9') c = getchar(); 
        while(c <= '9' && c >= '0')x = x * 10 + c- '0',c = getchar(); 
        return x ; 
    } 
    #define pi acos(-1.0) 
    struct Complex {
        double x,y; 
        Complex(double a = 0,double b = 0) : x(a),y(b)  {}; 
    } ;
    Complex operator + (Complex a,Complex b) { return Complex(a.x + b.x,a.y + b.y);} 
    Complex operator - (Complex a,Complex b) { return Complex(a.x - b.x,a.y - b.y);} 
    Complex operator * (Complex a,Complex b) { return Complex(a.x * b.x - a.y * b.y,a.x * b.y + a.y * b.x);} 
    
    const int maxn = 1000007; 
    int n;
    Complex A[maxn],B[maxn],C[maxn];  
    void fft(Complex *a,int n,int type) { 
        for(int i = 0,j = 0;i < n;++ i) { 
            if(i < j) std::swap(a[i],a[j]); 
            for(int k = n >> 1;(j ^= k) < k;k >>= 1);
        } 
        for(int m = 2;m <= n;m <<= 1) { 
            Complex w1 = Complex (cos(2 * pi / m),type * sin(2 * pi / m)); 
            for(int i = 0;i < n;i += m) { 
                Complex w = Complex(1,0); 
                for(int k = 0;k < (m >> 1);++ k) {
                    Complex t = w * a[i + k + (m >> 1)],u = a[i + k]; 
                    a[i + k] = u + t; 
                    a[i + k + (m >> 1)] = u - t; 
                    w = w  * w1; 
                } 
            } 
        } 
    } 
    Complex ans[maxn]; 
    int main() { 
        n = read(); int lim = 0; 
        for(int tmp,i = 1;i <= n;++ i) { 
            tmp = read(); 
            A[tmp] = Complex(1,0); 
            B[tmp * 2] = Complex(1,0); 
            C[tmp * 3] = Complex(1,0); 
            lim = std::max(lim,tmp * 3); 
        } 
        for(n = 1;n <= lim;n <<= 1); 
        fft(A,n,1); 
            fft(B,n,1); 
        fft(C,n,1); 
        for(int i = 0;i < n;++ i) 
            ans[i] = A[i] + (A[i] * A[i] - B[i]) * Complex(1.0 / 2.0,0) + (A[i] * A[i] * A[i] - A[i] * B[i] * Complex(3.0,0) + Complex(2.0,0) * C[i]) * Complex(1.0 / 6.0,0); 
        fft(ans,n,-1); 
        for(int i = 0;i < n;++ i) { 
            int T = ans[i].x / n + 0.5; 
            if(T) printf("%d %d
    ",i,T); 
        }   
        return 0; 
    }   
    fft
    /*
    苟活者在淡红的血色中,会依稀看到微茫的希望
    */
     
    #include<bits/stdc++.h>
    using namespace std;
    inline int read() {
        int   x = 0,f = 1;
        char c = getchar();
        while(c < '0' || c > '9'){if(c == '-')f = - 1; c =  getchar(); }
        while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
        return x * f;
    }
    const int maxn = 1000007;
    const int P = 998244353,G = 3,Gi = 332748118;
    #define LL long long
    LL pre[maxn],now[maxn];
    int n,m,limit = 1,k,prek,K,L,r[maxn];
    inline LL fastpow(LL a, LL k) {
        LL base = 1;
        while(k) {
            if(k & 1) base = (base * a ) % P;
            a = (a * a) % P;
            k >>= 1;
        }
        return (base % P + P) % P;
    }
    inline void NTT(LL *A, int type) {
        for(int i = 0; i < limit; i++)
            if(i < r[i]) swap(A[i], A[r[i]]);
        for(int mid = 1; mid < limit; mid <<= 1) { 
            LL Wn = fastpow( type == 1 ? G : Gi , (P - 1) / (mid << 1));
            for(int j = 0; j < limit; j += (mid << 1)) {
                LL w = 1;
                for(int k = 0; k < mid; k++, w = (w * Wn) % P) {
                     int x = A[j + k], y = w * A[j + k + mid] % P;
                     A[j + k] = (x + y) % P,
                     A[j + k + mid] = (x - y + P) % P;
                }
            }
        }
    }
    LL inv[maxn];
    void work(int k,int prek) {
        limit = 1;
        L = 0;
        for(int c = 1,i = 1;i <= k;++ i) now[i] = c = 1ll * c * (k - i + 1) % P * inv[i] % P;
        while(limit <= k + prek) limit <<= 1,L ++;
        for(int i = 0;i < limit;++ i)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
        NTT(now,1);NTT(pre,1);
        for(int i = 0;i < limit;++ i) now[i] = (now[i] * pre[i]) % P;
        NTT(now,-1);
        LL inv = fastpow(limit, P - 2);
        for(int i = 0;i <= k + prek;++ i) now[i] = (now[i] * inv) % P;
    } 
    int t[maxn]; 
    int main() {
        n = read(); m = read(),K = read();
        prek = read() ; 
        for(int i = 1;i <= prek;++ i) pre[i] = 1;
        inv[1] = 1; 
        for(int i = 2;i <= m;++ i) t[i - 1] = read(); 
        random_shuffle(t + 1,t + m); 
        for(int i = 2; i <= n; ++ i)
            inv[i]=1ll*(P-P/i)* inv[P % i] % P;
        for(int k = 0,i = 1;i < m;++ i) {
            k = t[i]; 
            work(k,prek);
            for(int i = 0;i <= k + prek;++ i) pre[i] = now[i],now[i] = r[i] = 0;
            prek = k + prek;
        }
        printf("%d
    ",pre[K]);
        return 0;
    } 
    ntt
  • 相关阅读:
    geoserver 地图性能和缓存
    geoserver PostGIS的安装和使用
    geoserver 数据图层输出格式
    Centos7Yum安装配置指定版本nginx
    Centos7Yum安装PHP7.2
    CentOS7 中把默认yum源更换成163源
    安装配置Elasticserch的方法
    redis的持久化(RDB&AOF的区别)
    LayerDate渲染多个class出现闪现问题的解决
    explain分析SQL语句详解
  • 原文地址:https://www.cnblogs.com/sssy/p/7358978.html
Copyright © 2011-2022 走看看