模板

快速读入
fread
namespace fastIO {
    #define BUF_SIZE 100000
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void rd(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror) return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;


普通快速读入
inline int IN(int &x)
{
  char c;int f=1;
  x=0;
  for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
  for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
  return f*x;
}


快速幂+快速乘


inline LL multi(LL a,LL b)
{
  LL ans=0;
  while(b)
  {
    if(b&1)ans=(ans+a)%mod;
    a=(a+a)%mod;
    b>>=1; 
  }
  return (ans+mod)%mod;
}

inline LL Pow(LL a,LL b)
{
  LL ans=1;
  while(b)
  {
    if(b&1)ans=multi(ans,a)%mod;
    a=multi(a,a)%mod;
    b>>=1; 
  }
  return (ans+mod)%mod;
}


KMP

nxt[0]=0;nxt[1]=0;
int j=0;
for(int i=2;i<=m;++i)
{
  while(j&&b[i]!=b[j+1])j=nxt[j];
  if(b[i]==b[j+1])j++;
  nxt[i]=j;
}

j=0;
int k=-1;
for(int i=1;i<=n&&k==-1;++i)
{
  while(j&&a[i]!=b[j+1])j=nxt[j];
  if(a[i]==b[j+1])j++;
  if(j==m)
  {
    k=i;
    break;
  }
}


AC自动机

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;

int cnt,root,n;
char s[maxn];
int fail[maxn],last[maxn];


struct node
{
  int nxt[26],cnt;
}T[maxn];

inline int newnode()
{
  cnt++;
  memset(T[cnt].nxt,0,sizeof(T[cnt].nxt));
  T[cnt].cnt=0;
  fail[cnt]=0;
  last[cnt]=0;
  return cnt;
}

inline void insert(char *s)
{
  int now=root;
  int i=0;
  while(s[i])
  {
    if(!T[now].nxt[s[i]-'a'])T[now].nxt[s[i]-'a']=newnode();
    now=T[now].nxt[s[i]-'a'];
    i++;
  }
  T[now].cnt++;
}

queue<int>Q;
inline void build()
{
  Q.push(root);
  while(!Q.empty())
  {
    int k=Q.front();
    Q.pop();
    for(int i=0;i<26;++i)
    {
      if(!T[k].nxt[i]){T[k].nxt[i]=T[fail[k]].nxt[i];continue;}

      if(k!=root)
      {
        fail[T[k].nxt[i]]=T[fail[k]].nxt[i];
        last[T[k].nxt[i]]=T[T[k].nxt[i]].cnt?fail[T[k].nxt[i]]:last[fail[T[k].nxt[i]]];
      }
      Q.push(T[k].nxt[i]);
    }
  }
}


inline int find(char *s)
{
  int k=root;
  int cnt=0;
  int i=0;
  while(s[i])
  {
    int x=s[i]-'a';
    k=T[k].nxt[x];

    int p=k;
    while(p!=root&&T[p].cnt>=0)
    {
      cnt+=T[p].cnt;
      T[p].cnt=-1;
      p=last[p];
    }
    i++;
  }
  return cnt;
}

int main()
{
  int t;
  scanf("%d",&t);
  while(t--)
  { 
    cnt=-1;
    root=newnode();
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
      scanf("%s",s);
      insert(s);
    }

    build();
    scanf("%s",s);
    printf("%d\n",find(s));
  }
  return 0;
}


AC自动机上DP+DFS序转RMQ线段树维护区间修改

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=3e5+5;

int cnt,root,n,kase,w[20000+5],pos[20000+5];
int INDEX,in[maxn],out[maxn];
char s[maxn];
int fail[maxn];

int S[maxn*4],tag[maxn*4],MAX,L,R;
int st[maxn],tot;

struct edge
{
  int v,nxt;
}v[maxn*2];

inline void addedge(int x,int y)
{
  v[tot]=(edge){y,st[x]};
  st[x]=tot++;
}

struct node
{
  int nxt[26],cnt;
}T[maxn];

inline int newnode()
{
  cnt++;
  memset(T[cnt].nxt,0,sizeof(T[cnt].nxt));
  T[cnt].cnt=0;
  fail[cnt]=0;
  return cnt;
}

inline void insert(char *s)
{
  int now=root;
  int i=0;
  while(s[i])
  {
      if(!T[now].nxt[s[i]-'a'])T[now].nxt[s[i]-'a']=newnode();
      now=T[now].nxt[s[i]-'a'];
      i++;
  }
  T[now].cnt++;
}

queue<int>Q;
inline void build()
{
  Q.push(root);
  while(!Q.empty())
  {
      int k=Q.front();
      Q.pop();
      if(k!=root)addedge(fail[k],k);
      for(int i=0;i<26;++i)
      {
        if(!T[k].nxt[i]){T[k].nxt[i]=T[fail[k]].nxt[i];continue;}

      if(k!=root)
      {
        fail[T[k].nxt[i]]=T[fail[k]].nxt[i];
      }
        Q.push(T[k].nxt[i]);
      }
  }
}

inline void DFS(int u,int fa)
{
  in[u]=++INDEX;
  for(int i=st[u];~i;i=v[i].nxt)
  if(v[i].v!=fa)DFS(v[i].v,u);
  out[u]=INDEX;
}

inline void update(int k)
{
  S[k]=max(S[k<<1],S[k<<1|1]);
}

inline void down(int k)
{
  if(!tag[k])return ;
  tag[k<<1]=max(tag[k<<1],tag[k]); 
  tag[k<<1|1]=max(tag[k<<1|1],tag[k]);
  S[k<<1]=max(S[k<<1],tag[k]);
  S[k<<1|1]=max(S[k<<1|1],tag[k]);
  tag[k]=0;
}

inline int ask(int l,int r,int k)
{
  if(L<=l&&r<=R)return S[k];
  int mid=(l+r)>>1;
  down(k);
  int res=0;
  if(L<=mid)res=max(res,ask(l,mid,k<<1));
  if(R>mid)res=max(res,ask(mid+1,r,k<<1|1));
  return res;  
}

inline void add(int l,int r,int k)
{
  if(L<=l&&r<=R)
  {
      S[k]=max(S[k],MAX);
      tag[k]=max(tag[k],MAX);
      return ;
  }
  int mid=(l+r)>>1;
  down(k);
  if(L<=mid)add(l,mid,k<<1);
  if(R>mid)add(mid+1,r,k<<1|1);
  update(k);
}

int main()
{
  int t;
  scanf("%d",&t);
  while(t--)
  { 
    scanf("%d",&n);
    cnt=-1;
    root=newnode();
    tot=0;
    memset(st,-1,sizeof(st));

    pos[0]=0;
    for(int i=1;i<=n;++i)
    {
      scanf("%s%d",s+pos[i-1],w+i);
      pos[i]=pos[i-1]+strlen(s+pos[i-1]);
      insert(s+pos[i-1]);
    }

    build();

    INDEX=0;
    DFS(root,-1);

    int ans=0;
    memset(S,0,sizeof(S));
    memset(tag,0,sizeof(tag));

    for(int i=1;i<=n;++i)
    {
      MAX=0;
      int p=root;
      for(int j=pos[i-1];j<pos[i];++j)
      {
          p=T[p].nxt[s[j]-'a'];

          L=in[p];R=in[p];
          int res=ask(1,INDEX,1);
          MAX=max(res,MAX);

      }
      MAX=MAX+w[i];
      ans=max(ans,MAX);
      L=in[p];R=out[p];
      add(1,INDEX,1);
    }

    printf("Case #%d: %d\n",++kase,ans);
  }
  return 0;
}

主席树静态区间第K大
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
struct node
{
    int l,r,siz;
}T[40*maxn];
int root[maxn],n,m,cnt,l,r,ll,rr,v[maxn],pos,w[maxn],d,kth;

inline int get_id(int x)
{
    return lower_bound(w,w+d,x)-w+1;
}

inline int build(int l,int r)
{
    int k=cnt++;
    if(l==r)
    {
        T[k].siz=0;
        return k;
    }
    int mid=(l+r)>>1;
    T[k].l=build(l,mid);
    T[k].r=build(mid+1,r);
    T[k].siz=0;
    //printf("l=%d r=%d ld=%d rd=%d  k=%d\n",l,r,T[k].l,T[k].r,k);
    return k;
}

inline int add(int l,int r,int k)
{
    int now=cnt++;
    T[now]=T[k];
    if(l==pos&&r==pos)
    {
        T[now].siz+=1;
        return now;
    }
    int mid=(l+r)>>1;
    if(mid>=pos)T[now].l=add(l,mid,T[k].l);
    else T[now].r=add(mid+1,r,T[k].r);
    T[now].siz=T[T[now].l].siz+T[T[now].r].siz;
    return now;
}

inline int quiry(int l,int r,int ll,int rr,int kth)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int tmp=T[T[rr].l].siz-T[T[ll].l].siz;
    if(tmp>=kth)return quiry(l,mid,T[ll].l,T[rr].l,kth);
    else return quiry(mid+1,r,T[ll].r,T[rr].r,kth-tmp);
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        cnt=0;
        for(int i=0;i<n;++i)
        {
            scanf("%d",&v[i]);
            w[i]=v[i];
        }
        sort(w,w+n);
        d=unique(w,w+n)-w;

        root[0]=build(1,d);
        for(int i=1;i<=n;++i)
        {
            pos=get_id(v[i-1]);
            root[i]=add(1,d,root[i-1]);
        }
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&l,&r,&kth);
            printf("%d\n",w[quiry(1,d,root[l-1],root[r],kth)-1]);
        }
    }
    return 0;
}

整体二分动态区间第K大
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e4 + 7;
const int M = 1e5 + 7;
const int INF = 1 << 30;

struct Quiry
{
  int x,y,z,id,tp;
}Q[ N + M ],q1[ N + M ],q2[ N + M ];

int n,m,cnt,a[N],ans[N],x,y,z,idx;

struct Bit
{
  int T[N];
  int n;
  inline void init(int c){n=c;memset(T, 0, sizeof(T));}
  inline void add(int x,int y){for(;x<=n;x+=x&-x)T[x] += y;}
  inline int sum(int u)
  {
    int ans = 0;
    for(;u;u-=u&-u)ans += T[u];
    return ans;
  }
}BIT;

inline void solve(int l,int r,int AL,int AR)
{
  if(l>r)return;
  if(AL==AR)
  {
    for(int i=l;i<=r;++i)
    if(Q[i].tp==2) ans[Q[i].id] = AL;
    return;
  }

  int AM = (AL + AR) >> 1;
  int p1=0,p2=0;

  for(int i=l;i<=r;++i)
  {
    if(Q[i].tp==1)
    {
      if(Q[i].x<=AM)
      {
        BIT.add(Q[i].id,Q[i].y);
        q1[++p1] = Q[i];
      }
      else q2[++p2] = Q[i];
    }
    else
    {
      int del = BIT.sum(Q[i].y) - BIT.sum(Q[i].x-1);
      if(del >= Q[i].z)q1[++p1] = Q[i];
      else
      {
        Q[i].z -= del;
        q2[++p2] = Q[i];
      }
    }
  }
    for(int i=1;i<=p1;++i)if(q1[i].tp==1)BIT.add(q1[i].id,-q1[i].y);

    for(int i=1;i<=p1;++i)Q[i+l-1] = q1[i];
    for(int i=1;i<=p2;++i)Q[i+p1+l-1] = q2[i];

    solve(l,l+p1-1,AL,AM);
    solve(l+p1,r,AM+1,AR);

}

int main()
{
  int T;
  scanf("%d\n",&T);
  while(T--)
 {
  scanf("%d%d\n",&n,&m);
  cnt = idx = 0;
  for(int i=1;i<=n;++i)
  {
    scanf("%d",a+i);
    Q[++cnt] = (Quiry){a[i],1,0,i,1};
  }
  for(int i=1;i<=m;++i)
  {
    char opt[2];
    scanf("%s%d%d",opt,&x,&y);
    if(*opt=='Q')
    {
      scanf("%d\n",&z);
      ++idx;
      Q[++cnt] = (Quiry){x,y,z,idx,2};
    }
    else
    {
      Q[++cnt] = (Quiry){a[x],-1,0,x,1};
      a[x]=y;
      Q[++cnt] = (Quiry){a[x],1,0,x,1};
    }
  }
  BIT.init(n);
  solve(1,cnt,-INF,INF);
  for(int i=1;i<=idx;++i)printf("%d\n",ans[i]);
 }
  return 0;
}

分块求区间小于x的和
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
const int maxn=2e5+5,INF=1<<30;

int pos[maxn],siz,n,m,x,ll[maxn],rr[maxn];
int a[maxn],b[maxn];

int main()
{
  int t;
  scanf("%d",&t); 
  while(t--)
  {
    scanf("%d%d",&n,&m);

    memset(ll,0,sizeof(ll));
    siz=floor(sqrt(n)+0.5);
    for(int i=1;i<=n;++i)
    {
      scanf("%d",&a[i]);
      b[i]=a[i];

      pos[i]=(i-1)/siz+1;
      if(!ll[pos[i]])ll[pos[i]]=i;
      rr[pos[i]]=i;
    }
    int maxsize=(n-1)/siz+1;
    int L,R;
    for(int i=1;i<=maxsize;++i)
    {
      sort(b+ll[i],b+1+rr[i]);
    }

    for(int i=1;i<=m;++i)
    {
      scanf("%d%d%d",&L,&R,&x);
      int idl=pos[L],idr=pos[R];
      int res=0;
      if(idl!=idr)
      {

        for(int j=L;j<=rr[idl];++j)
        if(a[j]<x)res++;

        for(int j=ll[idr];j<=R;++j)
        if(a[j]<x)res++;

        for(int j=idl+1;j<idr;++j)
        {
          int y=lower_bound(b+ll[j],b+1+rr[j],x)-b;
          if(b[y]>=x||y==rr[j]+1)y--;
          if(y>=ll[j])res+=y-ll[j]+1;
        }
      }
      else
      {
        for(int j=L;j<=R;++j)
        if(a[j]<x)res++;
      }
      printf("%d\n",res);
    }
  }
  return 0;
} 


莫队分块-小Z的袜子
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=50000+5;
typedef long long LL;
struct pp
{
    int l,r,id;
    LL ans1,ans2;
}a[maxn];

LL c[maxn],sum[maxn],ans;
int n,m,pos[maxn];
inline bool cmp(const pp &A,const pp &B)
{
    return pos[A.l]<pos[B.l]||(pos[A.l]==pos[B.l]&&A.r<B.r);
}

inline bool cmp2(const pp &A,const pp &B)
{
    return A.id<B.id;
}

inline LL gcd(LL a,LL b)
{
    if(!b)return a;
    return gcd(b,a%b);
}

inline void modify(int p,int del)
{
    ans+=(LL)2*del*sum[c[p]]+1;
    sum[c[p]]+=del;
}

int main()
{
  while(scanf("%d%d",&n,&m)!=EOF)
  {
      memset(sum,0,sizeof(sum));
      for(int i=1;i<=n;++i)scanf("%lld",&c[i]);
      for(int i=1;i<=m;++i)scanf("%d%d",&a[i].l,&a[i].r),a[i].id=i;
      int siz=floor(sqrt(n));
      for(int i=1;i<=n;++i)pos[i]=(i-1)/siz+1;

      sort(a+1,a+1+m,cmp);

      ans=0;
      int L=1,R=0;
      for(int i=1;i<=m;++i)
      {
          if(a[i].r>R)
          {
              for(R=R+1;R<=a[i].r;++R)modify(R,+1);
              --R;
          }
          if(a[i].r<R)for(;R>a[i].r;--R)modify(R,-1);
          if(a[i].l>L)for(;a[i].l>L;++L)modify(L,-1);
          if(a[i].l<L)
          {
              for(L=L-1;a[i].l<=L;--L)modify(L,+1);
              L++;
          }
          if(a[i].l==a[i].r)
          {
              a[i].ans1=0;
              a[i].ans2=1;
              continue;
          }
          a[i].ans1=ans-(a[i].r-a[i].l+1);
          a[i].ans2=(LL)(a[i].r-a[i].l)*(a[i].r-a[i].l+1);

          //printf("test=%lld/%lld\n",a[i].ans1,a[i].ans2);
          LL GCD=gcd(a[i].ans1,a[i].ans2);
          a[i].ans1/=GCD;
          a[i].ans2/=GCD;
      }
      sort(a+1,a+1+m,cmp2);
      for(int i=1;i<=m;++i)printf("%lld/%lld\n",a[i].ans1,a[i].ans2);
  }
  return 0;
}

树链剖分-树状数组动态权值和


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int n,m,start,end,cnt,k,index,opt;
int fa[maxn],st[maxn],dep[maxn];
int top[maxn],son[maxn],size[maxn],id[maxn];
int T[maxn],a[maxn];

struct node
{
  int ed,w,nxt;
}v[maxn*2];

inline void add(int x,int y,int z)
{
  v[cnt]=(node){y,z,st[x]};
  st[x]=cnt++;
}

inline void dfs(int u,int f)
{
  fa[u]=f;
  son[u]=0;size[u]=1;dep[u]=dep[f]+1;
  int ma=0;
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=f)
    {
      dfs(y,u);
      size[u]+=size[y];
      if(size[y]>ma)son[u]=y;
    }
  }
}

inline void DFS(int u,int tp)
{
  top[u]=tp;
  id[u]=++index;
  if(son[u])DFS(son[u],tp);
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=fa[u]&&y!=son[u])DFS(y,y);
  }
}

inline void update(int x,int val)
{
  for(;x<=n;x+=x&-x)T[x]+=val;
}

inline int get(int x)
{
  int res=0;
  for(;x;x-=x&-x)res+=T[x];
  return res;
}

inline int quiry(int u,int v)
{
  int x=top[u],y=top[v];
  int ans=0;
  while(x!=y)
  {
    if(dep[x]<dep[y])swap(x,y),swap(u,v);
    ans+=get(id[u])-get(id[x]-1);
    u=fa[x];
    x=top[u];
  }
  if(u==v)return ans;
  if(dep[u]<dep[v])swap(u,v);
  ans+=get(id[u])-get(id[v]);
  return ans;
}

int main()
{
  while(~scanf("%d%d%d",&n,&m,&start))
  {
    memset(st,-1,sizeof(st));
    cnt=0;
    int x,y,z;
    for(int i=1;i<n;++i)
    {
      scanf("%d%d%d",&x,&y,&z);
      add(x,y,z);
      add(y,x,z);
    }
    dfs(1,0);
    index=0;
    DFS(1,1);

    memset(T,0,sizeof(T));
    for(int i=0;i<2*n-2;i+=2)
    {
      int x=v[i].ed,y=v[i^1].ed;
      if(dep[x]<dep[y])swap(x,y);
      a[id[x]]=v[i].w;
      update(id[x],v[i].w);
    }

    for(int i=1;i<=m;++i)
    {
      scanf("%d",&opt);
      if(opt)
      {
        scanf("%d%d",&x,&y);
        int u=v[2*x-2].ed,z=v[2*x-1].ed;
        if(dep[u]<dep[z])swap(u,z);
        update(id[u],-a[id[u]]);
        a[id[u]]=y;
        update(id[u],y);
      }
      else
      {
        scanf("%d",&end);
        printf("%d\n",quiry(start,end));
        start=end;
      }
    }

  }
  return 0;
}


树链剖分-线段树动态权值和
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int n,m,start,end,cnt,k,index,opt,L,R;
int fa[maxn],st[maxn],dep[maxn];
int top[maxn],son[maxn],size[maxn],id[maxn];
int T[maxn*4],a[maxn],leaf[maxn];

struct node
{
  int ed,w,nxt;
}v[maxn*2];

inline void add(int x,int y,int z)
{
  v[cnt]=(node){y,z,st[x]};
  st[x]=cnt++;
}

inline void dfs(int u,int f)
{
  fa[u]=f;
  son[u]=0;size[u]=1;dep[u]=dep[f]+1;
  int ma=0;
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=f)
    {
      dfs(y,u);
      size[u]+=size[y];
      if(size[y]>ma)son[u]=y;
    }
  }
}

inline void DFS(int u,int tp)
{
  top[u]=tp;
  id[u]=++index;
  if(son[u])DFS(son[u],tp);
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=fa[u]&&y!=son[u])DFS(y,y);
  }
}

inline void update(int k)
{
  T[k]=T[k<<1]+T[k<<1|1];
}

inline void build(int l,int r,int k)
{
  if(l==r)
  {
    T[k]=a[l];
    leaf[l]=k;
    return;
  }
  int mid=(l+r)>>1;
  build(l,mid,k<<1);
  build(mid+1,r,k<<1|1);
  update(k);
}

inline int ask(int l,int r,int k)
{
  if(L<=l&&r<=R)return T[k];
  int mid=(l+r)>>1;
  int res=0;
  if(L<=mid)res+=ask(l,mid,k<<1);
  if(R>mid)res+=ask(mid+1,r,k<<1|1);
  return res;  
}

inline void modify(int x)
{
  int k=leaf[x];
  T[k]=a[x];
  k>>=1;
  for(;k;k>>=1)update(k);
}

inline int quiry(int u,int v)
{
  int x=top[u],y=top[v];
  int ans=0;
  while(x!=y)
  {
    if(dep[x]<dep[y])swap(x,y),swap(u,v);
    //ans+=get(id[u])-get(id[x]-1);
    L=id[x],R=id[u];
    ans+=ask(1,n,1);
    u=fa[x];
    x=top[u];
  }
  if(u==v)return ans;
  if(dep[u]<dep[v])swap(u,v);
  L=id[v]+1,R=id[u];
  ans+=ask(1,n,1);
  return ans;
}

int main()
{
  while(~scanf("%d%d%d",&n,&m,&start))
  {
    memset(st,-1,sizeof(st));
    cnt=0;
    int x,y,z;
    for(int i=1;i<n;++i)
    {
      scanf("%d%d%d",&x,&y,&z);
      add(x,y,z);
      add(y,x,z);
    }
    dfs(1,0);
    index=0;
    DFS(1,1);

    memset(T,0,sizeof(T));
    for(int i=0;i<2*n-2;i+=2)
    {
      int x=v[i].ed,y=v[i^1].ed;
      if(dep[x]<dep[y])swap(x,y);
      a[id[x]]=v[i].w;
    }

    build(1,n,1);

    for(int i=1;i<=m;++i)
    {
      scanf("%d",&opt);
      if(opt)
      {
        scanf("%d%d",&x,&y);
        int u=v[2*x-2].ed,z=v[2*x-1].ed;
        if(dep[u]<dep[z])swap(u,z);
        a[id[u]]=y;
        modify(id[u]);
      }
      else
      {
        scanf("%d",&end);
        printf("%d\n",quiry(start,end));
        start=end;
      }
    }

  }
  return 0;
}

树链剖分-不带修改的树上路径权值[A,B]的和询问-离线树状数组

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int n,m,start,end,cnt,k,index,opt;
int fa[maxn],st[maxn],dep[maxn];
int top[maxn],son[maxn],size[maxn],id[maxn];
LL T[maxn],ans[maxn];
int a,b,x,y,z;

struct node
{
  int ed,nxt;
}v[maxn*2];

struct Lv
{
  int d,id;
}w[maxn];

struct Quiry
{
  int u,v,val,id,ty;
}Q[maxn*2];

inline bool cmp(const Lv&A,const Lv&B)
{
  return A.d<B.d;
}

inline bool cmp2(const Quiry&A,const Quiry&B)
{
  return A.val<B.val;
}

inline void add(int x,int y)
{
  v[cnt]=(node){y,st[x]};
  st[x]=cnt++;
}

inline void dfs(int u,int f)
{
  fa[u]=f;
  son[u]=0;size[u]=1;dep[u]=dep[f]+1;
  int ma=0;
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=f)
    {
      dfs(y,u);
      size[u]+=size[y];
      if(size[y]>ma)son[u]=y;
    }
  }
}

inline void DFS(int u,int tp)
{
  top[u]=tp;
  id[u]=++index;
  if(son[u])DFS(son[u],tp);
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(y!=fa[u]&&y!=son[u])DFS(y,y);
  }
}

inline void update(int x,LL val)
{
  for(;x<=n;x+=x&-x)T[x]+=val;
}

inline LL get(int x)
{
  LL res=0;
  for(;x;x-=x&-x)res+=T[x];
  return res;
}

inline LL quiry(int u,int v)
{
  int x=top[u],y=top[v];
  LL ans=0;
  while(x!=y)
  {
    if(dep[x]<dep[y])swap(x,y),swap(u,v);
    ans+=get(id[u])-get(id[x]-1);
    u=fa[x];
    x=top[u];
  }
  if(u==v)return ans+get(id[u])-get(id[u]-1);
  if(dep[u]<dep[v])swap(u,v);
  ans+=get(id[u])-get(id[v]-1);
  return ans;
}

int main()
{
  while(~scanf("%d%d",&n,&m))
  {
    memset(st,-1,sizeof(st));
    cnt=0;
    for(int i=1;i<=n;++i)
    {
      scanf("%d",&w[i].d);
      w[i].id=i; 
    }
    sort(w+1,w+1+n,cmp);
    for(int i=1;i<n;++i)
    {
      scanf("%d%d",&x,&y);
      add(x,y);
      add(y,x);
    }
    dfs(1,0);
    index=0;
    DFS(1,1);
    cnt=0;
    for(int i=1;i<=m;++i)
    {
      scanf("%d%d%d%d",&x,&y,&a,&b);
      Q[++cnt]=(Quiry){x,y,a-1,i,-1};
      Q[++cnt]=(Quiry){x,y,b,i,1};
    }

    sort(Q+1,Q+1+cnt,cmp2);

    memset(T,0,sizeof(T));
    memset(ans,0,sizeof(ans));
    int L=1;
    for(int i=1;i<=cnt;++i)
    {
      while(L<=n&&w[L].d<=Q[i].val)
      {
        update(id[w[L].id],w[L].d);
        L++;
      }
      ans[Q[i].id]+=(LL)Q[i].ty*quiry(Q[i].u,Q[i].v);
    }
    for(int i=1;i<m;++i)printf("%lld ",ans[i]);
    printf("%lld\n",ans[m]);
  }
  return 0;
}

倍增LCA-树上权值和
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int  N =100010;
struct Edge
{
    int x,w;
    Edge(int x,int w):x(x),w(w){}
};
vector<Edge> g[N];
vector<int> vec[N];
int fa[N][20],dep[N],h[N];
int n,Q;
void dfs(int x,int p)
{
    h[x]=h[p]+1;
    fa[x][0]=p;
    for(int i=1;i<20;++i)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    int y;
    for(int i=0;i<g[x].size();++i)
    {
        y=g[x][i].x;
        if(y==p) continue;
        dep[y]=dep[x]+g[x][i].w;
        dfs(y,x);
    }
}
int lca(int x,int y)
{
    if(h[x]<h[y]) swap(x,y);
    int d=h[x]-h[y];
    for(int i=0;i<20;++i)
        if((d>>i)&1) x=fa[x][i];
    if(x==y) return x;
    for(int i=19;i>=0;--i)
        if(fa[x][i]!=fa[y][i])
        {
            x=fa[x][i];y=fa[y][i];
        }
    return fa[x][0];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&Q);
        for(int i=1;i<=n;++i) g[i].clear();
        int x,y,w;
        for(int i=1;i<n;++i)
        {
            scanf("%d%d%d",&x,&y,&w);
            g[x].push_back(Edge(y,w));
            g[y].push_back(Edge(x,w));
        }
        dfs(1,0);
        int u,v,ans;
        while(Q--)
        {
            scanf("%d%d",&u,&v);
            ans=dep[u]+dep[v]-2*dep[lca(u,v)];
            printf("%d\n",ans);
        }
    }
    return 0;
}

高斯消元
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const double eps=1e-8;
const int MAXN=1e3;
typedef double Matrix[MAXN][MAXN];
Matrix a;//m行n+1列,从0开始
//增广矩阵,即a[i][n]是方程右边的常数
//结束后a[i][n]是第i个未知数的值

int dcmp(double x)//浮点数比较
{
    if(fabs(x)<eps) return 0;
    return x<0?-1:1;
}

void Gauss(Matrix &a,int m,int n)
{
    //变成行阶梯形矩阵
    for(int i=0;i<m;++i)
    {
        //列选主元
        int r=i;
        for(int j=i+1;j<m;++j)
        {
            if(fabs(a[j][i])>fabs(a[r][i])) r=j;
        }
        if(r!=i) for(int j=0;j<=n;++j) swap(a[r][j],a[i][j]);

        //与第i+1~m-1行进行消元
        for(int k=i+1;k<m;++k)
        {
            double f=a[k][i]/a[i][i];
            for(int j=i;j<=n;++j) a[k][j]-=f*a[i][j];
        }
    }
}

//n元线性方程组
int solve(Matrix &a,int m,int n)
{
    Gauss(a,m,n);
    int r1=0;//系数矩阵的秩
    int r2=0;//增广矩阵的秩
    for(int i=0;i<m;++i)
    {
        bool zero=true;
        for(int j=0;j<=n;j++)
        {
            if(dcmp(a[i][j]))
            {
                if(j<n) r1++;
                r2++;
                zero=false;
                break;
            }
        }
        if(zero||r1<r2) break;
    }
    if(r1<r2) return -1;//无解
    else if(r1==r2&&r1<n) return 0;//有无穷多解
    else
    {
        //回代
        for(int i=n-1;i>=0;--i)
        {
            for(int j=i+1;j<n;++j)
            {
                a[i][n]-=a[j][n]*a[i][j];
            }
            a[i][n]/=a[i][i];
        }
        return 1;//有唯一解
    }
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<m;++i)
        {
            for(int j=0;j<=n;++j)
            {
                scanf("%lf",&a[i][j]);
            }
        }
        int ans=solve(a,m,n);
        if(ans<0) printf("No solutions\n");
        else if(ans==0) printf("Many solutions\n");
        else
        {
            for(int i=0;i<n;++i)
            {
                printf("%d\n",(int)(a[i][n]+0.5));
            }
        }
    }
    return 0;
}



RMQ
const int maxn=1e5+5;

int a[maxn],T[4*maxn],n,res[maxn],L,R,leaf[maxn];
//Segment Tree


inline void update(int k)
{
  T[k]=T[k<<1]+T[k<<1|1];
}

inline void build(int l,int r,int k)
{
  if(l==r)
  {
    T[k]=a[l];
    leaf[l]=k;
    return;
  }
  int mid=(l+r)>>1;
  build(l,mid,k<<1);
  build(mid+1,r,k<<1|1);
  update(k);
}

inline int ask(int l,int r,int k)
{
  if(L<=l&&r<=R)return T[k];
  int mid=(l+r)>>1;
  int res=0;
  if(L<=mid)res+=ask(l,mid,k<<1);
  if(R>mid)res+=ask(mid+1,r,k<<1|1);
  return res;  
}

inline void modify(int x)
{
  int k=leaf[x];
  T[k]=a[x];
  k>>=1;
  for(;k;k>>=1)update(k);
}


//ST table
void rmq_init()
{
   for(int i=1; i<=n; i++) f[i][0] = a[i];
   int k=floor(log((double)n)/log(2.0));
   for(int j=1; j<=k; j++)
      for(int i=n; i>=1; i--)
      {
         if(i+(1<<(j-1))<=n)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
      }
}
int rmq(int i,int j)
{
    int k = floor(log((double)(j-i+1))/log(2.0));
    return max(f[i][k],f[j-(1<<k)+1][k]);    
}

匈牙利算法-矩阵
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;
int G[maxn][maxn],a[maxn*maxn],b[maxn*maxn],obj[maxn];
bool used[maxn];
int n,m,k,kase;

inline bool DFS(int u)
{
  for(int i=1;i<=m;++i)
  if(G[u][i]&&used[i]==0)
  {
    used[i]=1;
    if(obj[i]==0||DFS(obj[i]))
    {
      obj[i]=u;
      return 1;
    }
  }
  return 0;
}

inline int Hungarian()
{
  int res=0;
  memset(obj,0,sizeof(obj));
  for(int i=1;i<=n;++i)
  {
    memset(used,0,sizeof(used));
    if(DFS(i))res++;
  }
  return res;
}

int main()
{
  while(~scanf("%d%d%d",&n,&m,&k))
  {
    memset(G,0,sizeof(G));
    for(int i=1;i<=k;++i)
    {
      scanf("%d%d",a+i,b+i);
      G[a[i]][b[i]]=1;
    }

    int MAX=Hungarian(),ans=0;
    for(int i=1;i<=k;++i)
    {
      G[a[i]][b[i]]=0;
      int res=Hungarian();
      G[a[i]][b[i]]=1;
      if(res<MAX)ans++;
    }
    printf("Board %d have %d important blanks for %d chessmen.\n",++kase,ans,MAX);
  }
  return 0;
}

匈牙利算法-邻接表
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5,maxm=maxn*maxn;
int st[maxn],obj[maxn];
bool used[maxn];
int n,m,k,x,y,z,cnt;
struct node
{
  int ed,nxt;
}v[maxm];

inline void add(int x,int y)
{
  ++cnt;
  v[cnt]=(node){y,st[x]};
  st[x]=cnt;
}

inline bool DFS(int u)
{
  for(int x=st[u];x;x=v[x].nxt)
  {
    int y=v[x].ed;
    if(used[y]==0)
    {
      used[y]=1;
      if(obj[y]==-1||DFS(obj[y]))
      {
        obj[y]=u;
        return 1;
      }
    }
  }
  return 0;
}

inline int Hungarian()
{
  int res=0;
  memset(obj,-1,sizeof(obj));
  for(int i=1;i<n;++i)
  {
    memset(used,0,sizeof(used));
    if(DFS(i))res++;
  }
  return res;
}

int main()
{
  while(~scanf("%d%d%d",&n,&m,&k)&&n)
  {
    memset(st,0,sizeof(st));
    cnt=0;
    for(int i=1;i<=k;++i)
    {
      scanf("%d%d%d",&z,&x,&y);
      if(x==0||y==0)continue;
      add(x,y);
    }

    int MAX=Hungarian();
    printf("%d\n",MAX);
  }
  return 0;
}


带权二分图最大匹配KM
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=200+5,maxm=maxn*maxn,INF=1<<28;
typedef pair<int,int> pai;

char s[maxn];
int n,m,cnt,pos,ed;
int lx[maxn],ly[maxn],slack[maxn],w[maxn],obj[maxn];
bool visx[maxn],visy[maxn];
vector<pai>M,H;

int st[maxn];
struct node
{
  int v,nxt,w;
}v[maxm];

inline void add(int x,int y,int c,int z)
{
  v[cnt]=(node){y,st[x],z};
  st[x]=cnt++;
}

inline bool DFS(int u)
{
  visx[u]=1;
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].v;
    if(visy[y])continue;
    if(lx[u]+ly[y]==v[x].w)
    {
      visy[y]=1;
      if(obj[y]==-1||DFS(obj[y]))
      {
        obj[y]=u;
        w[y]=v[x].w;
        return 1;
      }
    }else slack[y]=min(slack[y],lx[u]+ly[y]-v[x].w);
  }
  return 0;
}

inline void KM()
{
  for(int i=1;i<=M.size();++i)lx[i]=-INF,ly[i]=0;
  for(int i=1;i<=M.size();++i)
    for(int x=st[i];~x;x=v[x].nxt)
      lx[i]=max(lx[i],v[x].w);//min

  for(int i=1;i<=M.size();++i)
  {
    for(int j=1;j<=H.size();++j)slack[j]=INF;
    while(1)
    {
      memset(visx,0,sizeof(visx));
      memset(visy,0,sizeof(visy));
      if(DFS(i))break;

      int d=INF;
      for(int j=1;j<=H.size();++j)
        if(!visy[j])d=min(d,slack[j]);

      for(int j=1;j<=H.size();++j)
      {
        if(visx[j])lx[j]-=d;
        if(visy[j])ly[j]+=d;
        else slack[j]-=d;
      }
    }
  }
}

int main()
{
  while(~scanf("%d%d",&n,&m))
  {
    if(!n&&!m)break;
    memset(st,-1,sizeof(st));
    memset(obj,-1,sizeof(obj));
    memset(w,0,sizeof(w));
    cnt=0;
    H.clear();M.clear();
    for(int i=0;i<n;++i)
    {
      scanf("%s",s);
      for(int j=0;j<m;++j)
      if(s[j]=='H')H.push_back(pai(i,j));
      else if(s[j]=='m')M.push_back(pai(i,j));
    }

    for(int i=0;i<M.size();++i)
    {
      pos=i+1;
      for(int j=0;j<H.size();++j)
      {
        int ed=j+1;
        int cost=abs(M[i].first-H[j].first)+abs(M[i].second-H[j].second); 

        add(pos,ed,1,-cost);
      }
    }
    KM();
    int ans=0;
    for(int i=1;i<=H.size();++i)ans-=w[i];
    printf("%d\n",ans);
  }
  return 0;
}


最大流
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=500+5,maxm=maxn*maxn,INF=1<<30;

int n,src,des,x,y,z,m;
int st[maxn],stp[maxn],cnt;

struct node
{
  int v,w,nxt;
}v[maxm];

inline void add(int x,int y,int z)
{
  v[cnt]=(node){y,z,st[x]};
  st[x]=cnt++;
}

queue<int>Q;
inline bool bfs()
{
  memset(stp,-1,sizeof(stp));
  while(!Q.empty())Q.pop();
  stp[src]=0;
  Q.push(src);

  while(!Q.empty())
  {
    int u=Q.front();
    Q.pop();
    for(int x=st[u];~x;x=v[x].nxt)
    {
      int y=v[x].v;
      if(v[x].w>0&&stp[y]==-1)
      {
        stp[y]=stp[u]+1;
        Q.push(y);
      }
    }
  }
  return stp[des]!=-1;
}

inline int dfs(int u,int f)
{
  if(u==des)return f;
  int res;
  for(int x=st[u];~x;x=v[x].nxt)
  {
    int y=v[x].v;
    if(v[x].w>0&&stp[y]==stp[u]+1)
    {
      res=dfs(y,min(f,v[x].w));
      if(res>0)
      {
        v[x].w-=res;
        v[x^1].w+=res;
        return res;
      }
    }
  }
  stp[u]=-1;
  return 0;
}

inline int Dinic()
{
  int ans=0,res;
  while(bfs())
  {
    while(res=dfs(src,INF))
    {
      ans+=res;
    }
  }
  return ans;
}

int main()
{
  while(~scanf("%d%d",&n,&m))
  {
    cnt=0;
    memset(st,-1,sizeof(st));
    src=1;des=m;

    for(int i=1;i<=n;++i)
    {
      scanf("%d%d%d",&x,&y,&z);
      add(x,y,z);
      add(y,x,-z);
    }

    int res=Dinic();

    printf("%d\n",res);
  }
  return 0;
}

最小费用最大流MCMF

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

typedef long long LL;

const int M=2010;
const int N=510;

struct edge
{
    int to;
    int next;
    int cap;
    int cost;
} e[11000];

int head[N],tot;
int d[N], pre[N], path[N];
bool vis[N];

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void addedge(int s, int t, int cap, int cost)
{
    e[tot].to=t;
    e[tot].cap=cap;
    e[tot].cost=cost;
    e[tot].next=head[s];
    head[s] = tot++;
    e[tot].to=s;
    e[tot].cap=0;
    e[tot].cost=-cost;
    e[tot].next=head[t];
    head[t] = tot++;
}

int spfa(int s, int t)
{
    memset(d,-INF,sizeof(d));
    memset(pre,-1,sizeof(pre));
    memset(path,-1,sizeof(path));
    memset(vis,false,sizeof(vis));
    int res = d[0];
    d[s] = 0;
    vis[s] = true;
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for (int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if (d[v] < d[u] + e[i].cost && e[i].cap > 0)
            {
                d[v] = d[u] + e[i].cost;
                pre[v] = u;
                path[v] = i;
                if (!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return d[t] != res;
}

int MinCostMaxFlow(int s, int t,int &cost)
{
    int flow;
    flow=cost=0;
    while (spfa(s, t))
    {
        int minn = INF;
        for (int i = t; i != s && ~i; i = pre[i])
            minn = min(minn, e[path[i]].cap);
        for (int i = t; i != s && ~i; i = pre[i])
        {
            e[path[i]].cap -= minn;
            e[path[i] ^ 1].cap += minn;
        }
        if (d[t] < 0)
            break;
        flow += minn;
        cost += minn * d[t];
    }
    return flow;
}

int main(void)
{
    int n,m;
    while (cin>>n>>m)
    {
        init();
        int s=0,t=n+1,cost;
        for (int i=1; i<=n; i++)
        {
            int a,b,c,d;
            cin>>a>>b>>c>>d;
            addedge(s,i,b,-a);
            addedge(i,t,d,c);
        }
        while (m--)
        {
            int u,v,k;
            cin>>u>>v>>k;
            addedge(u,v,INF,-k);
            addedge(v,u,INF,-k);
        }
        MinCostMaxFlow(s,t,cost);
        cout<<cost<<endl;
    }
    return 0;
}
//http://blog.csdn.net/qq_28954601/article/details/77149389 


Dj+Heap

struct Heap
{
  int dis,u;
  bool operator <(const Heap&B) const
  {
    return dis>B.dis;
  }
};
priority_queue<Heap> Q;

inline void Dj(int s)
{
  memset(inq,0,sizeof(inq));
  memset(dis,127,sizeof(dis));
  while(!Q.empty())Q.pop();
  dis[s]=0;
  Q.push((Heap){0,s});

  while(!Q.empty())
  {
    Heap New=Q.top();
    Q.pop();
    if(inq[New.u])continue;

    int k=New.u;
    inq[k]=1;
    for(int x=st[k];x;x=a[x].next)
    {
      int y=a[x].ed;
      if(!vis[y]&&dis[y]>dis[k]+a[x].w)
      {
        dis[y]=dis[k]+a[x].w;
        Q.push((Heap){dis[y],y});
      }
    }
  }
}

Dj次短路
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1e5+5;
const LL INF=1ll<<60;

struct edge
{
    int to;
    LL cost;
    edge(LL tv = 0, LL tc = 0):to(tv), cost(tc){}
};
typedef pair<LL ,LL> P;
int N, M, A, B, D;
vector<edge> graph[MAXN];
priority_queue<P, vector<P>, greater<P> > Q;
LL dist[MAXN];
LL dist2[MAXN];

void solve(){
    //fill(dist, dist+N, INF);
    //fill(dist2, dist2+N, INF);
    for(int i = 1; i <= N;++i)dist[i]=dist2[i]=INF;
    while(!Q.empty())Q.pop();
    dist[1] = 0;
    Q.push(P(0, 1));
    while(!Q.empty())
    {
        P p = Q.top(); Q.pop();

        LL v = p.second, d = p.first;

        if(dist2[v] < d) continue;
        for(LL i = 0; i < graph[v].size(); i++)
        {
            edge e = graph[v][i];
            LL d2 = d + e.cost;
            if(dist[e.to] > d2)
            {
                swap(dist[e.to], d2);
                Q.push(P(dist[e.to], e.to));
            }
            if(dist2[e.to] > d2 && dist[v] < d2)
            {
                dist2[e.to] = d2;
                Q.push(P(dist2[e.to], e.to));
            }
        }
    }
}

int main()
{
  int t;
  scanf("%d",&t);
  while(t--) 
  {
    scanf("%d%d", &N, &M);
    int MIN=1<<30;
    for(LL i = 1; i <= N;++i)graph[i].clear();
    for(LL i = 0; i < M; i++)
    {
        scanf("%d%d%d", &A, &B, &D);
        graph[A].push_back(edge(B, D));
        graph[B].push_back(edge(A, D));
        if(A==N||B==N)MIN=min(D,MIN); 
    }
    solve();
    LL ans=min(dist[N]+(LL)MIN*2,dist2[N]);
    printf("%lld\n",ans);
  }
  return 0;
}


SPFA

inline void SPFA(int s)
{
  memset(dis,127,sizeof(dis));
  memset(inq,0,sizeof(inq));
  int l=0,r=0;
  q[++r]=s;
  inq[s]=1;
  dis[s]=0;
  while(l<r)
  {
    int k=q[++l];
    inq[k]=0;
    for(int x=st[k];x;x=a[x].next)  
    {
      int y=a[x].ed;
      if(dis[y]>dis[k]+a[x].val)
      {
        dis[y]=dis[k]+a[x].val;
        if(!inq[y])
        {
          inq[y]=1;
          q[++r]=y;
        }
      }
    }
  }
}

哈夫曼编码
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e6+5;
//typedef pair<int,int> pai;
typedef long long LL;

struct pai
{
  LL cnt,len;
  bool operator <(const pai &B)const
  {
    return (cnt>B.cnt)||(cnt==B.cnt&&len>B.len);
  }
};
LL n,k,sum,ans,w[maxn];
priority_queue<pai>Q;
int main()
{
  while(~scanf("%lld%lld",&n,&k))
  {
    while(!Q.empty())Q.pop();
    for(int i=1;i<=n;++i)scanf("%lld",w+i);
    while(k!=2&&n%(k-1)!=1)w[++n]=0;
    for(int i=1;i<=n;++i)Q.push((pai){w[i],0});
    ans=0;
    while(Q.size()!=1)
    {
      LL sum=0,L=0;
      pai now={0,0};
      for(int i=1;i<=k;++i)
      {
        now=Q.top();
        Q.pop();
        sum+=now.cnt;
        L=max(now.len,L);
      }
      now.cnt=sum;
      now.len=L+1;
      Q.push(now);
      ans+=sum;
    }
    pai now=Q.top();
    printf("%lld\n%lld\n",ans,now.len);
  }
  return 0;
}


Lucas定理

const int MAXN = 1010;  
const int mod = 1e9 + 7;  
LL inv[MAXN + 10], fac[MAXN + 10];  
void init()    
{    
    inv[0] = fac[0] = inv[1] = fac[1] = 1;    
    for(int i = 1; i < MAXN; i++)    
    fac[i] = fac[i - 1] * i % mod;    
    for(int i = 2; i < MAXN; i++)    
    inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;//lucas定理求逆元    
    for(int i = 1; i < MAXN; i++)    
    inv[i] = inv[i - 1] * inv[i] % mod;     
}  
inline LL C(int n, int m)//求组合数 C n,m     
{    
    if(n<m)return 0; 
    return (fac[n] * inv[m] % mod) * inv[n - m] %mod;     
}    


欧拉线性筛->莫比乌斯函数+欧拉函数

int n,m,T,kase,mobius[maxn],cnt[maxn],L,R;
LL ans;
bool vis[maxn];
int prime[maxn],phi[maxn];
inline void get_mobius()
{
  int L=0;
  mobius[1]=1;
  phi[1]=1;
  for(int i=2;i<maxn;++i)
  {
    if(!vis[i])mobius[i]=-1,prime[++L]=i,phi[i]=i-1;
    for(int j=1;i*prime[j]<maxn&&j<=L;++j)
    {
      mobius[i*prime[j]]-=mobius[i];
      phi[i*prime[j]]=phi[i]*phi[prime[j]];
      vis[i*prime[j]]=1;
      if(i%prime[j]==0)
      {
        mobius[i*prime[j]]=0;
        phi[i*prime[j]]=phi[i]*prime[j];
        break;
      }
    }
  }
}


莫比乌斯反演+区间差分线段覆盖
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=1e6,mod=1e9+7;
int n,m;
LL F[maxn+5],f[maxn+5];
bool vis[maxn+5];
int prime[maxn+5],mobius[maxn+5];

inline void get()
{
  int L=0;
  mobius[1]=1;
  for(int i=2;i<=maxn;++i)
  {
    if(!vis[i])prime[++L]=i,mobius[i]=-1;
    for(int j=1;i*prime[j]<=maxn&&j<=L;++j)
    {
      vis[i*prime[j]]=1;
      mobius[i*prime[j]]-=mobius[i];
      if(i%prime[j]==0)
      {
        mobius[i*prime[j]]=0;
        break;
      }
    }
  }
}

int main()
{
  get();
  for(int i=1;i<=maxn;++i)
  {
     F[i]++;
     for(int j=i+1;j<=maxn;j+=i)
     F[j]++;
  }

  for(int i=1;i<=maxn;++i)F[i]=(F[i-1]+F[i])%mod;

  for(int i=1;i<=maxn;++i)
  if(mobius[i])
  {
    for(int j=i;j<=maxn;j+=i)f[j]=(f[j]+mobius[i]*F[j/i])%mod;
  }
  for(int i=1;i<=maxn;++i)f[i]=(f[i]+f[i-1])%mod;
  while(~scanf("%d",&n))
  {
    printf("%lld\n",(f[n]+mod)%mod);
  }
  return 0;
}


扩展欧几里得算法EXGCD
/* 本程序仅用于求整数解,即当C满足模gcd(a,b)为0时可应用*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>

using namespace std;

int a,b,c,x,y,t,x0,y0;

inline int exgcd(int a,int b)
{
    if (b==0) { x=1; y=0; return a; } // ax+by=gcd(a,b)->b=0,ax=gcd(a,0)=a->x=1,y=0
    int T=exgcd(b,a%b),t=x; x=y; y=t-(a/b)*x; return T;
    /*  因为gcd(a,b)=gcd(b,a%b) 根据定理:ax+by=gcd(a,b) 
        ax+by=bx1+(a%b)y1 -> ax+by=bx1+(a-(a/b)*b)y1[c++中 /相当于div ] 
        ax+by=ay1+b(x1-(a/b)*y1) 
        所以x=y1,y=x1-(a/b)*y1 */
}

int main()
{
    freopen("exgcd.in","r",stdin);
    freopen("exgcd.out","w",stdout);
    scanf("%d%d%d",&a,&b,&c);
    t=exgcd(a,b); x0=x*(c/t); y0=y*(c/t); //对于c不是gcd(a,b)的情况。 
    printf("%d %d",x0,y0);
    return 0;
}
/*  本程序求出的是一个基础解,由基础解可求出其他整数解:
    对于ax+by=gcd(a,b):
    X=x+b/gcd(a,b)*t,Y=y-a/gcd(a,b)*t,
    对于ax+by=c:
    X=x0+b/gcd(a,b)*t,Y=y0-a/gcd(a,b)*t, 其中t为任意整数 */




Prim&Kruskal

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500+5,INF=1<<28;
int v[maxn][maxn],n,m,ans,dis[maxn];
bool inque[maxn];
inline void prim()
{ 
    memset(inque,0,sizeof(inque));
    for(int i=1;i<=n;++i)dis[i]=v[1][i];
    inque[1]=1;
    ans=0;

    for(int i=2;i<=n;++i)
    {
      int mini=INF,k=-1;
      for(int j=1;j<=n;++j)
      if(!inque[j]&&dis[j]<mini)
      {
        mini=dis[j];
        k=j;
      }

      ans=max(ans,mini);
      inque[k]=1;
      for(int j=1;j<=n;++j)
      if(!inque[j]&&dis[j]>v[k][j])dis[j]=v[k][j];
    }
}

//const int maxn=3000+5,maxm=100000+5;
struct nod
{
  int u,v,w;
}a[maxn];

int fa[maxn];

inline bool cmp(const nod&A,const nod&B)
{
  return A.w<B.w;
}

inline int get(int u)
{
  if(fa[u]==u)return u;
  return fa[u]=get(fa[u]);
}

inline void kruskal()
{
    for(int i=1;i<=m;++i)scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
    for(int i=1;i<=n;++i)fa[i]=i;
    int size=n;

    sort(a+1,a+1+m,cmp);

    for(int i=1;i<=m;++i)
    {
      int fx=get(a[i].u),fy=get(a[i].v);
      if(fx!=fy)
      {
        fa[fx]=fy;
        size--;
      }
    }
}

int main()
{
  return 0;
}

数位DP

typedef long long ll;
int a[20];
ll dp[20][state];//不同题目状态不同
ll dfs(int pos,/*state变量*/,bool lead/*前导零*/,bool limit/*数位上界变量*/)//不是每个题都要判断前导零
{
    //递归边界,既然是按位枚举,最低位是0,那么pos==-1说明这个数我枚举完了
    if(pos==-1) return 1;/*这里一般返回1,表示你枚举的这个数是合法的,那么这里就需要你在枚举时必须每一位都要满足题目条件,也就是说当前枚举到pos位,一定要保证前面已经枚举的数位是合法的。不过具体题目不同或者写法不同的话不一定要返回1 */
    //第二个就是记忆化(在此前可能不同题目还能有一些剪枝)
    if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];
    /*常规写法都是在没有限制的条件记忆化,这里与下面记录状态是对应,具体为什么是有条件的记忆化后面会讲*/
    int up=limit?a[pos]:9;//根据limit判断枚举的上界up;这个的例子前面用213讲过了
    ll ans=0;
    //开始计数
    for(int i=0;i<=up;i++)//枚举,然后把不同情况的个数加到ans就可以了
    {
        if() ...s
        else if()...
        ans+=dfs(pos-1,/*状态转移*/,lead && i==0,limit && i==a[pos]) //最后两个变量传参都是这样写的
        /*这里还算比较灵活,不过做几个题就觉得这里也是套路了
        大概就是说,我当前数位枚举的数是i,然后根据题目的约束条件分类讨论
        去计算不同情况下的个数,还有要根据state变量来保证i的合法性,比如题目
        要求数位上不能有62连续出现,那么就是state就是要保存前一位pre,然后分类,
        前一位如果是6那么这意味就不能是2,这里一定要保存枚举的这个数是合法*/
    }
    //计算完,记录状态
    if(!limit && !lead) dp[pos][state]=ans;
    /*这里对应上面的记忆化,在一定条件下时记录,保证一致性,当然如果约束条件不需要考虑lead,这里就是lead就完全不用考虑了*/
    return ans;
}
ll solve(ll x)
{
    int pos=0;
    while(x)//把数位都分解出来
    {
        a[pos++]=x%10;//个人老是喜欢编号为[0,pos),看不惯的就按自己习惯来,反正注意数位边界就行
        x/=10;
    }
    return dfs(pos-1/*从最高位开始枚举*/,/*一系列状态 */,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛
}
int main()
{
    ll le,ri;
    while(~scanf("%lld%lld",&le,&ri))
    {
        //初始化dp数组为-1,这里还有更加优美的优化,后面讲
        printf("%lld\n",solve(ri)-solve(le-1));
    }
}
//http://blog.csdn.net/wust_zzwh/article/details/52100392


矩阵快速幂

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=4;

LL n , MOD;
struct Matrix
{
  LL mat[N][N];
  void init()
  {
    memset(mat,0,sizeof(mat));
    mat[0][0]=mat[0][2]=mat[0][3]=1;
    mat[1][0]=mat[2][1]=mat[3][2]=1;
  }

  void clear()
  {
    memset(mat,0,sizeof(mat));
    for(int i = 0 ; i < N ; i++)mat[i][i]=1;
  }

  Matrix operator*(const Matrix& m)const
  {
    Matrix tmp;
    for(int i = 0 ; i < N ; i++)
    {
      for(int j = 0 ; j < N ; j++)
      {
          tmp.mat[i][j] = 0;
          for(int k = 0 ; k < N ; k++)
          {
            tmp.mat[i][j] += mat[i][k]*m.mat[k][j]%MOD;
            tmp.mat[i][j] %= MOD;
          }
      }
    }
    return tmp;
  }
}a;

LL Pow(Matrix &a,LL b)
{
    if(b <= 3)return (2*n)%MOD;
    if(b == 4)return 9%MOD;
    b -= 4;
    Matrix ans;
    ans.clear();
    while(b){
        if(b&1)ans=ans*a;
        b>>=1;
        a=a*a;
    }

    LL sum = 0;
    sum += ans.mat[0][0]*9%MOD;
    sum += ans.mat[0][1]*6%MOD;
    sum += ans.mat[0][2]*4%MOD;
    sum += ans.mat[0][3]*2%MOD;
    return sum%MOD;
}

int main()
{
  while(~scanf("%lld%lld",&n,&MOD))
  {
    a.init();
    printf("%lld\n",Pow(a,n));
  }
  return 0;
}

不相交线段转换+连续代价小于x的最大覆盖数
#include <iostream>  
#include <cstring>  
#include <algorithm>  
using namespace std;  
const int maxn=1000010;
int n,m;
struct node {  
  int a,b;  
}x[maxn];
int l[maxn],r[maxn];

inline bool cmp(node x1, node x2){return x1.a<x2.a||(x1.a==x2.a&&x1.b < x2.b);} 

int main()  
{  
  while(~scanf("%d%d",&n,&m))
  {
    for(int i=1; i<=n; i++)scanf("%d%d",&x[i].a,&x[i].b); 
    sort(x+1, x+n+1, cmp);  
    int cnt=1;
    l[1]=x[1].a;r[1]=x[1].b; 
    for(int i=2; i<=n; i++)  
    {  
      if(x[i].a<=r[cnt])r[cnt]=max(r[cnt],x[i].b);
      else ++cnt,l[cnt]=x[i].a,r[cnt]=x[i].b;
    }  
    int ans=r[1]-l[1]+1+m,L=1,res=0;
    for(int i=2;i<=cnt;++i)
    {
        res+=l[i]-r[i-1]-1;
        while(res>m)
        {
          res-=l[L+1]-r[L]-1;
          L++;
        }

        ans=max(ans,r[i]-l[L]+1+m-res);
    }

    printf("%d\n",ans); 
  }
  return 0;  
}  

归并排序求逆序对
LL ans;
int a[maxn],n,b[maxn];

inline void merge(int l,int r)
{
  if(l>=r)return;
  int mid=(l+r)>>1;
  merge(l,mid);
  merge(mid+1,r);
  int L=l,R=mid+1;
  int cnt=l;
  while(L<=mid||R<=r)
  {
    if(L>mid||(a[R]<a[L]&&R<=r))
    {
      b[cnt++]=a[R++];
      ans+=mid-L+1;
    }
    else b[cnt++]=a[L++];
  }
  for(int i=l;i<=r;++i)a[i]=b[i];
}

Splay-数组实现
#include<cstdio>
#define N 2000100
using namespace std;
struct node
{
  int l,r,d,size,fa;
  void reset()
  {
    l=r=d=size=fa=0;
  }
}T[N];
int cnt,i,j,m,n,k,root=1,now;

inline void updata(int u)//update
{
  T[u].size=T[T[u].l].size+T[T[u].r].size+1;
}

inline void zag(int s)//left_rotate
{
  int x=T[s].fa,y=T[x].fa,z=T[s].l;
  if(T[y].l==x)T[y].l=s;else T[y].r=s;
  T[s].fa=y;
  T[x].r=z;T[z].fa=x;
  T[s].l=x;T[x].fa=s;
  updata(x);
  updata(s);
}

inline void zig(int s)//right_rotate
{
  int x=T[s].fa,y=T[x].fa,z=T[s].r;
  if(T[y].l==x)T[y].l=s;else T[y].r=s;
  T[s].fa=y;
  T[x].l=z;T[z].fa=x;
  T[s].r=x;T[x].fa=s;
  updata(x);
  updata(s);
}

inline void splay(int s)
{
  while(T[s].fa)
  {
    int x=T[s].fa,y=T[x].fa;
    if(y)
    {
      if(T[y].l==x)
      {
        if(T[x].l==s)zig(x),zig(s);
        else zag(s),zig(s);
      }
      else
      {
        if(T[x].l==s)zig(s),zag(s);
        else zag(x),zag(s);
      }
    }
  else if(T[x].l==s)zig(s);else zag(s);
  }
  root=s;
}

inline int findkth(int x)//寻找第k大返回指针 
{
  int s=root;
  while(1)
  {
    if(x==T[T[s].l].size+1)return s;
    if(x<=T[T[s].l].size)s=T[s].l;
    else x=x-T[T[s].l].size-1,s=T[s].r;
  }
}

inline int getkth(int x)//寻找x是第k大返回k
{
  int s=root;
  int sum=0;
  while(1&&s)
  {
    if(x==T[s].d)return sum+T[T[s].l].size+1;
    else if(x<T[s].d)s=T[s].l;
    else sum+=T[T[s].l].size+1,s=T[s].r;
  }
  return sum;
}

inline void insert(int x)//插入x 
{
  int s=root;
  if(!cnt){T[++cnt].reset();T[cnt].d=x;T[cnt].size=1;return;}
  while(1)
  {
    if(!T[s].d){T[s].d=x;T[s].size=1;return;}
    if(x<T[s].d)
    {
      if(!T[s].l){T[s].l=++cnt;T[cnt].fa=s;}
      T[s].size++;
      s=T[s].l;
    }
    else
    {
      if(!T[s].r){T[s].r=++cnt;T[cnt].fa=s;}
      T[s].size++;
      s=T[s].r;
    }
  }
}

inline void del(int x)
{
  int y=findkth(x);
  splay(y);
  if(T[y].l==0&&T[y].r==0)
  {
    cnt=0;return;
  }
  if(T[y].l==0)
  {
    T[T[y].r].fa=0;
    root=T[y].r;
    return;
  }
  if(T[y].r==0)
  {
    T[T[y].l].fa=0;
    root=T[y].l;
    return;
  }
  int d=getkth(x);
  int z=findkth(d-1);
  T[z].r=T[y].r;
  T[T[y].r].fa=z;
  root=T[y].l;
  T[root].fa=0;
  splay(z);
}

int main()
{
  scanf("%d",&n);
  cnt=0; 
  for(i=1;i<=n;++i)
  {
    scanf("%d",&now);
    insert(now);
    //if(i&1)printf("%d\n",find((i>>1)+1,root));
    //if(!(i%7))splay(root);
  }
  return 0;
}


Splay序列修改-指针
#include <cstdio>
#include <cstring>

using namespace std;
struct node
{
    char val;
    int size;
    node *lch, *rch, *pa;
    node(int s = 0, node *p = 0, char v = 0, node *l = 0, node *r = 0)
        : size(s), pa(p), val(v), lch(l), rch(r)
    {
    }
}*top;
struct pair
{
    node *first, *second;
    pair(node *fir = 0, node *sec = 0)
    {
        first = fir, second = sec;
    }
};
char s[100005];
int size(node *p)
{
    if (!p) return 0;
    return p->size;
}
node *Build(char *s, int len, node *p = 0)
{
    if (len == 0) return 0;
    if (len == 1) return new node(1, p, *s);
    node *res = new node;
    int mid = len >> 1;
    res->pa = p;
    res->val = s[mid];
    res->lch = Build(s, mid, res);
    res->rch = Build(s + mid + 1, len - mid - 1, res);
    res->size = size(res->lch) + size(res->rch) + 1;
    return res;
}
void update(node *x)
{
    if (x) x->size = size(x->lch) + size(x->rch) + 1;
}
node *rotate(node *x)
{
    node *y = x ->pa;
    x->pa = y->pa, y->pa = x;
    if (x->pa)
        (x->pa->lch == y) ? x->pa->lch = x : x->pa->rch = x;
    if (y->lch == x)
    {
        y->lch = x->rch, x->rch = y;
        if (y->lch) y->lch->pa = y;
    }else
    {
        y->rch = x->lch, x->lch = y;
        if (y->rch) y->rch->pa = y;
    }
    update(y), update(x);
    return x;
}
node *splay(node *x)
{
    node *y, *z;
    while (x->pa)
    {
        y = x->pa;
        if (!y->pa) rotate(x);
        else
        {
            z = y->pa;
            if (z->lch == y && y -> lch == x || z->rch == y && y->rch == x) rotate(x), rotate(x);
            else rotate(y), rotate(x);
        }
    }
    return x;
}
node *Find(node *t, int id)
{
    int s;
    while (true)
    {
        s = size(t->lch);
        if (s >= id) t = t->lch;
        else if (s + 1 == id) break;
        else t = t->rch, id -= s + 1;
    }
    return t;
}
node *Merge(node *x, node *y)
{
    if (!x) return y;
    x = Find(x, size(x));
    splay(x);
    x->rch = y;
    if (y) y->pa = x;
    update(x);
    return x;
}
pair Split(node *x, int idx)
{
    if (!idx) return pair(0, x);
    if (!(size(x) - idx)) return pair(x, 0);
    x = Find(x, idx), splay(x);
    node *y = x->rch;
    y->pa = x->rch = 0;
    update(x);
    return pair(x, y);
}
void Put_Front()
{
    int X, Y;
    scanf("%d%d", &X, &Y), X ++, Y ++;
    pair a = Split(top, X - 1);
    pair b = Split(a.second, Y - X + 1);
    top = Merge(b.first, Merge(a.first, b.second));
}
void Put_Back()
{
    int X, Y;
    scanf("%d%d", &X, &Y), X ++, Y ++;
    pair a = Split(top, X - 1);
    pair b = Split(a.second, Y - X + 1);
    top = Merge(Merge(a.first, b.second), b.first);
}
char Query()
{
    int idx;
    scanf("%d", &idx), idx ++;
    node *x = Find(top, idx);
    top = splay(x);
    return top->val;
}
int Q, opt;
int main()
{
    freopen("std.in", "r", stdin);
    freopen("Code.out", "w", stdout);
    scanf("%s", s);
    top = Build(s, strlen(s));
    scanf("%d", &Q);
    while (Q --)
    {
        scanf("%d", &opt);
        if (opt == 1) Put_Front();
        if (opt == 2) Put_Back();
        if (opt == 3) printf("%c\n", Query());
    }
    return 0;
}


可持久化Treap-指针
/*
    Treap[Merge,Split]
    by Memphis
*/

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
using namespace std;
#define maxn 2000005
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define dep(i,x,y) for(int i=x;i>=y;--i)

struct Treap{
    Treap *l,*r;
    int fix,key,size;
    Treap(int key_):fix(rand()),key(key_),l(NULL),r(NULL),size(1){}

    inline void updata(){
        size=1+(l?l->size:0)+(r?r->size:0);
    }
}*root;
typedef pair<Treap*,Treap*> Droot;//用来Split返回两个根 

inline int Size(Treap *x){return x?x->size:0;}//这样求size可以防止访问空指针 

Treap *Merge(Treap *A,Treap *B){//合并操作 
    if(!A)return B;
    if(!B)return A;
    if(A->fix<B->fix){
        A->r=Merge(A->r,B);
        A->updata();
        return A;
    }else{
        B->l=Merge(A,B->l);
        B->updata();
        return B;
    }
}

Droot Split(Treap *x,int k){//拆分操作 
    if(!x)return Droot(NULL,NULL);
    Droot y;
    if(Size(x->l)>=k){
        y=Split(x->l,k);
        x->l=y.second;
        x->updata();
        y.second=x;
    }else{
        y=Split(x->r,k-Size(x->l)-1);
        x->r=y.first;
        x->updata();
        y.first=x;
    }
    return y;
}

Treap *Build(int *a){//建造操作 
    static Treap *stack[maxn],*x,*last;
    int p=0;
    rep(i,1,a[0]){
        x=new Treap(a[i]);
        last=NULL;
        while(p && stack[p]->fix>x->fix){
            stack[p]->updata();
            last=stack[p];
            stack[p--]=NULL;
        }
        if(p) stack[p]->r=x;
        x->l=last;
        stack[++p]=x;
    }
    while(p) stack[p--]->updata();
    return stack[1];
}

int Findkth(int k){//查找第K小 
    Droot x=Split(root,k-1);
    Droot y=Split(x.second,1);
    Treap *ans=y.first;
    root=Merge(Merge(x.first,ans),y.second);
    return ans->key;
}

int Getkth(Treap *x,int v){//询问一个数是第几大 
    if(!x)return 0;
    return v<x->key?Getkth(x->l,v):Getkth(x->r,v)+Size(x->l)+1;
}

void Insert(int v){//插入操作 
    int k=Getkth(root,v);
    Droot x=Split(root,k);
    Treap *n=new Treap(v);
    root=Merge(Merge(x.first,n),x.second);
}

void Delete(int k){//删除操作 
    Droot x=Split(root,k-1);
    Droot y=Split(x.second,1);
    root=Merge(x.first,y.second);
}

int a[maxn],M,x,y;

int main(){
    freopen("bst.in","r",stdin);
    freopen("bst.out","w",stdout);

    scanf("%d",a);
    rep(i,1,a[0]) scanf("%d",a+i);
    sort(a+1,a+1+a[0]);
    root=Build(a);

    scanf("%d",&M);
    while(M--){
        char ch=getchar();
        while(ch!='Q' && ch!='A' && ch!='D') ch=getchar();
        scanf("%d",&x);
        if(ch=='Q') printf("%d\n",Findkth(x));
        if(ch=='A') Insert(x);
        if(ch=='D') Delete(x);
    }
}   


Treap

//fan_hd
#include <cstdio>
#include <cstdlib>
using namespace std;
class Treap{
    public:
        #define Max_N 1<<20
        struct point{
            int pri,val,father,left,right;
            point *left,*right;
        }p[Max_N];
        int length;
        int rand_arr[Max_N];
        void reset(int key){
            srand(time(0));
            for (int i=0;i!=key;rand_arr[i]=i++;)
            for (int i=0;i!=key;i++){
                int a=rand()%key,b=rand()%key;
                rand_arr[a]^=rand_arr[b],rand_arr[b]^=rand_arr[a],rand_arr[a]^=rand_arr[b]; //swap               
            }
            length=0;
            p[0].pri=-1;
            p[0].left=1;
        }
        inline void left_rotate(int now,int father){
            int now_right=p[now].right;
            p[now].right=father,p[father].left=now_right;
            p[now].father^=p[father].father,p[father].father^=p[now].father,p[now].father^=p[father].father;//swap
        }
        inline void right_rotate(int now,int father){
            int now_left=p[now].left;
            p[now].left=father,p[father].right=now_left;
            p[now].father^=p[father].father,p[father].father^=p[now].father,p[now].father^=p[father].father;//swap
        }
        void insert(int va,int pr){
            p[++length]={pr,va,0,0,0};
            if (length==1) return;
            for (int i=p[0].left,f;i;f=i,i=va>p[i].val?p[i].right:p[i].left);
            p[length].father=f;
            while (pr<p[p[length].father].pri){
                if (p[p[length].father].left==length) left_rotate(length,p[length].father);
                else right_rotate(length,p[length].father);
            }
        }
        int find(int v){
            for (int i=p[0].left;i;){
                if (p[i].val==v) return i;
                else i=v>p[i].val?p[i].right:p[i].left;
            }
            return -1;
        }
        void del(int v){
            int pos=find(v);
            if (pos+1==0) return;
            for(;;){
                if (pos[i])
            }
        }
        void print(){
        }
};
int main(){
    return 0;
}

FWT
#include<bits/stdc++.h>  
using namespace std;  
const int N=1e3+100,mod=1e9+7,rev=(mod+1)>>1;  
int a[N],ans[N];

void FWT(int *a,int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;  
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;  
                //and:a[i+j]=x+y;  
                //or:a[i+j+d]=x+y;  
            }  
}  

void UFWT(int *a,int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;  
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;  
                //and:a[i+j]=x-y;  
                //or:a[i+j+d]=y-x;  
            }  
}  
void solve(int *a,int *b,int n)  
{  
    FWT(a,n);  
    FWT(b,n);  
    for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;  
    UFWT(a,n);  
}  


FWT应用-CodeForces - 662C-FWTxor
#include<cstdio>
#include<cstring> 
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+5,maxm=(1<<20)+5;
LL a[maxn],b[maxm],f[maxm],n,m;
char s[maxn];

void FWT(LL *a,LL n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                LL x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y),a[i+j+d]=(x-y);
            }  
}  

void UFWT(LL *a,LL n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                LL x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;  
            }  
}  
void solve(LL *a,LL *b,LL n)  
{  
    FWT(a,n);  
    FWT(b,n);  
    for(int i=0;i<n;i++) a[i]=a[i]*b[i];  
    UFWT(a,n);  
}  

inline int calc(int x)
{
  int res=0;
  for(;x;x-=x&-x)res++;
  return res;
}

int main()
{
  scanf("%lld%lld",&n,&m);
  for(int i=0;i<n;++i)
  {
    scanf("%s",s);
    for(int j=0;j<m;++j)a[j]|=(s[j]=='1')<<i;
  }
  LL tot=(1<<n);
  for(int i=0;i<m;++i)b[a[i]]++;
  for(int i=0;i<tot;++i)
  {
    LL res=calc(i);
    f[i]=min(res,n-res);
  }
  solve(f,b,tot);
  LL ans=1e18;
  for(int i=0;i<tot;++i)ans=min(ans,f[i]);
  printf("%lld\n",ans);
  return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值