ACM模板(持续补完)

时间:2023-03-09 00:00:02
ACM模板(持续补完)

KMP

 #include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=;
char a[maxn+],s[maxn+];
int next[maxn+][maxn+];
int len1,len,t;
int main()
{
scanf("%d\n",&t);
while(t--)
{
s[]='';
scanf("%s",s+);
len=strlen(s);
for(int k=;k<len;++k)
{
int j=k-;
next[k][k]=k-;
for(int i=k+;i<len;++i)
{
while(j>=k&&s[j+]!=s[i]) j=next[k][j];
if(s[j+]==s[i]) ++j;
next[k][i]=j;
}
}
long long ans=;
for(int k=;k<len;++k)
{
int j=k-;
for(int i=;i<len;++i)
{
while(j>=k&&s[j+]!=s[i]) j=next[k][j];
if(s[j+]==s[i]) ++j;
ans^=1LL*(i-(j-k+))*(j-k+)*(j-k+)*(len--j);
if(j==len-) j=next[k][j];
}
}
printf("%lld\n",ans);
}
return ;
}

扩展KMP

 #include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e6;
char S[maxn+],T[maxn+];//S是母串,T是子串
int len1,len2;
int next[maxn+],extend[maxn+];//extend[i]表示S[i..len1-1]和T的最长公共前缀的长度,next[i]表示T[i..len2-1]和T的最长公共前缀的长度
void getnext()
{
next[]=len2;
int j=;
while(j+<len2&&T[j]==T[j+]) ++j;
next[]=j;
int k=;
for(int i=;i<len2;++i)
{
int p=k+next[k]-,l=next[i-k];
if(i+l<p+) next[i]=l;
else
{
j=max(p-i+,);
while(i+j<len2&&T[i+j]==T[j]) ++j;
next[i]=j;
k=i;
}
}
}
void ekmp()
{
int j=;
while(j<len1&&j<len2&&S[j]==T[j]) ++j;
extend[]=j;
int k=;
for(int i=;i<len1;++i)
{
int p=k+extend[k]-,l=next[i-k];//p表示到达的最远位置,k是对应最远位置的i
if(i+l<p+) extend[i]=l;
else
{
j=max(p-i+,);
while(i+j<len1&&j<len2&&S[i+j]==T[j]) ++j;
extend[i]=j;
k=i;
}
}
}
int main()
{
scanf("%s%s",S,T);
len1=strlen(S),len2=strlen(T);
getnext();
ekmp();
for(int i=;i<len1;++i) printf("%d ",extend[i]);
return ;
}

Manacher求最长回文子串

 #include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=;
char s[maxn*+];
int len=,mx=,id=;
int p[*maxn+];//p[i]表示以i为中心,向两边扩展的最长长度
char c;
int main()
{
s[]='$',s[]='#';
while(scanf("%c",&c)==) s[++len]=c,s[++len]='#';//在原字符串每个中间插上#,包括头尾,使得回文串长度为奇数,同时为了防止越界,第一个字符设为$
for(int i=;i<=len;++i)
{
if(mx>i) p[i]=min(p[*id-i],mx-i);else p[i]=;
while(s[i+p[i]]==s[i-p[i]]) ++p[i];
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}//O(n)求p数组
for(int i=;i<=len;++i) printf("%d ",p[i]);
return ;
}

后缀数组

 #include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
char s[maxn+];
int sa[maxn+],rk[maxn+],height[maxn+],d[maxn+][];
int t[maxn+],t2[maxn+],c[maxn+];
int len,k;
void getsa(int m)//m表示最大字符的编码
{
memset(t,-,sizeof(t));
memset(t2,-,sizeof(t2));
int *x=t,*y=t2;
for(int i=;i<m;++i) c[i]=;
for(int i=;i<len;++i) c[x[i]=s[i]]++;
for(int i=;i<m;++i) c[i]+=c[i-];
for(int i=len-;i>=;--i) sa[--c[x[i]]]=i;
for(int k=;k<=len;k<<=)
{
int p=;
for(int i=len-k;i<len;++i) y[p++]=i;
for(int i=;i<len;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=;i<m;++i) c[i]=;
for(int i=;i<len;++i) c[x[y[i]]]++;
for(int i=;i<m;++i) c[i]+=c[i-];
for(int i=len-;i>=;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=,x[sa[]]=;
for(int i=;i<len;++i)
if(y[sa[i-]]==y[sa[i]]&&y[sa[i-]+k]==y[sa[i]+k]) x[sa[i]]=p-;else x[sa[i]]=p++;
if(p>=len) break;
m=p;
}
}
void getheight()
{
int k=;
for(int i=;i<len;++i) rk[sa[i]]=i;
for(int i=;i<len;++i)
{
if(k) --k;
if(rk[i]==) continue;
int j=sa[rk[i]-];
while(s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
}
void rmq_init()
{
for(int i=;i<len;i++) d[i][]=height[i];
for(int j=;(<<j)-<=len;j++)
for(int i=;i+(<<j)-<len;i++)
d[i][j]=min(d[i][j-],d[i+(<<(j-))][j-]);
}
int lcp(int l,int r)
{
if(l<||r>=len) return ;
l=rk[l],r=rk[r];
if(l>r) swap(l,r);
++l;
int k=;
while((<<(k+))<=r-l+) k++;
return min(d[l][k],d[r-(<<k)+][k]);
}
int main()
{
scanf("%s",s);
len=strlen(s);
getsa('z'+);
getheight();
rmq_init();
int ans=;
for(int l=;l<=len;++l)
for(int i=;i<len;i+=l)
{
int m=lcp(i,i+l);
ans=max(ans,m/l+);
ans=max(ans,lcp(i-l+m%l,i+m%l)/l+);
}
printf("%d\n",ans);
// for(int i=0;i<n;++i) printf("%d ",sa[i]);printf("\n");
// for(int i=0;i<n;++i) printf("%d ",rk[i]);printf("\n");
// for(int i=0;i<n;++i) printf("%d ",height[i]);printf("\n");
return ; }

AC自动机

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int ch[maxn+][];
int sz=,n,root=;
char s[maxn+],S[maxn+];
int danger[maxn+];
int nx[maxn+];
int last[maxn+];
queue<int> q;
bool vis[maxn+];
void buildtrie(char *s)
{
int u=root;
int len=strlen(s);
for(int i=;i<len;++i)
{
int id=s[i]-'a';
if(!ch[u][id]) ch[u][id]=++sz;
u=ch[u][id];
}
++danger[u];
}
void buildfail()
{
while(!q.empty()) q.pop();
for(int i=;i<;++i) if(ch[root][i]) q.push(ch[root][i]),nx[ch[root][i]]=root,last[ch[root][i]]=;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=;i<;++i)
if(ch[u][i])
{
int k=nx[u];
while(!ch[k][i]&&k) k=nx[k];
nx[ch[u][i]]=ch[k][i];
//danger[ch[u][i]]|=danger[ch[k][i]];
if(danger[ch[k][i]]) last[ch[u][i]]=ch[k][i];else last[ch[u][i]]=last[ch[k][i]];
q.push(ch[u][i]);
}
else ch[u][i]=u==?:ch[nx[u]][i];
}
}
bool query(char *s)
{
int len=strlen(s);
int u=root;
int ans=;
for(int i=;i<len;++i)
{
int id=s[i]-'a';
u=ch[u][id];
int v=u;
while(v)
{
if(vis[v]) break;
vis[v]=;
if(danger[v]) ans+=danger[v],danger[v]=;
v=last[v];
}
}
return ans==n;
}
void init()
{
for(int i=;i<=sz;++i) memset(ch[i],,sizeof(ch[i]));
for(int i=;i<=sz;++i) danger[i]=;
for(int i=;i<=sz;++i) last[i]=;
for(int i=;i<=sz;++i) nx[i]=;
for(int i=;i<=sz;++i) vis[i]=;
sz=;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init();
int mx=;
for(int i=;i<=n;++i)
{
scanf("%s",s);
int l=strlen(s);
if(l>mx)
{
mx=l;
strcpy(S,s);
}
buildtrie(s);
}
buildfail();
if(query(S)) printf("%s\n",S);else printf("No\n");
}
return ;
}

树链剖分(bzoj1036)

 #include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=,inf=1e9;
struct wjmzbmr
{
int tid,top,size,son,dep,father,v;
}tree[maxn+];
struct fotile96
{
int maxnum,sum;
}f[*maxn+];
vector<int> g[maxn+];
int pos[maxn+];
int n,label=,q;
void dfs(int x,int fa,int dep)
{
tree[x]=(wjmzbmr){,,,,dep,fa,tree[x].v};
int m=;
for(int i=;i<g[x].size();++i)
if(g[x][i]!=fa)
{
dfs(g[x][i],x,dep+);
tree[x].size+=tree[g[x][i]].size;
if(tree[g[x][i]].size>m) m=tree[g[x][i]].size,tree[x].son=g[x][i];
}
}
void connect(int x,int top)
{
tree[x].tid=++label,pos[tree[x].tid]=x;
tree[x].top=top;
if(tree[x].son!=) connect(tree[x].son,top);
for(int i=;i<g[x].size();++i)
if(g[x][i]!=tree[x].father&&g[x][i]!=tree[x].son) connect(g[x][i],g[x][i]);
}
void make(int k,int l,int r)
{
if(l>r) return;
if(l==r) f[k].maxnum=f[k].sum=tree[pos[l]].v;
else
{
int mid=(l+r)>>;
make(k*,l,mid);
make(k*+,mid+,r);
f[k].sum=f[k*].sum+f[k*+].sum;
f[k].maxnum=max(f[k*].maxnum,f[k*+].maxnum);
}
}
void change(int k,int l,int r,int x,int y)
{
if(l>r||r<x||l>x) return;
if(l==r)
{
if(l==x) f[k].maxnum=y,f[k].sum=y;
return;
}
int mid=(l+r)>>;
change(k*,l,mid,x,y);
change(k*+,mid+,r,x,y);
f[k].sum=f[k*].sum+f[k*+].sum;
f[k].maxnum=max(f[k*].maxnum,f[k*+].maxnum);
}
int qqmax(int k,int l,int r,int ll,int rr)
{
if(l>r||l>rr||r<ll) return -inf;
if(l>=ll&&r<=rr) return f[k].maxnum;
int mid=(l+r)>>;
return max(qqmax(k*,l,mid,ll,rr),qqmax(k*+,mid+,r,ll,rr));
}
int qmax(int x,int y)
{
int ans=-inf;
while(tree[x].top!=tree[y].top)
{
if(tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
ans=max(ans,qqmax(,,n,tree[tree[x].top].tid,tree[x].tid));
x=tree[tree[x].top].father;
}
if(tree[x].dep>tree[y].dep) swap(x,y);
ans=max(ans,qqmax(,,n,tree[x].tid,tree[y].tid));
return ans;
}
int qqsum(int k,int l,int r,int ll,int rr)
{
if(l>r||l>rr||r<ll) return ;
if(l>=ll&&r<=rr) return f[k].sum;
int mid=(l+r)>>;
return qqsum(k*,l,mid,ll,rr)+qqsum(k*+,mid+,r,ll,rr);
}
int qsum(int x,int y)
{
int ans=;
while(tree[x].top!=tree[y].top)
{
if(tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
ans+=qqsum(,,n,tree[tree[x].top].tid,tree[x].tid);
x=tree[tree[x].top].father;
}
if(tree[x].dep>tree[y].dep) swap(x,y);
ans+=qqsum(,,n,tree[x].tid,tree[y].tid);
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) g[i].clear();
for(int i=;i<n;++i)
{
int x,y;
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=;i<=n;++i) scanf("%d",&tree[i].v);
dfs(,,);
connect(,);
make(,,n);
scanf("%d\n",&q);
for(int i=;i<=q;++i)
{
int x,y;
char s[];
scanf("%s %d %d\n",s,&x,&y);
if(s[]=='C') change(,,n,tree[x].tid,y);
if(s[]=='M') printf("%d\n",qmax(x,y));
if(s[]=='S') printf("%d\n",qsum(x,y));
}
return ;
}

treap实现名次树

 #include<cstring>
#include<algorithm>
#include<cstdio>
#include<ctime>
using namespace std;
const int maxn=;
struct xyz111
{
xyz111* ch[];
int value,key,size;
int cmp(int x)
{
if(value==x) return -;
return value<x;
}
void maintain()
{
size=;
if(ch[]!=NULL) size+=ch[]->size;
if(ch[]!=NULL) size+=ch[]->size;
}
};
xyz111* root=NULL;
int n;
void rorate(xyz111* &o,int d)
{
xyz111* k=o->ch[d^];
o->ch[d^]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
void insert(xyz111* &o,int x)
{
if(o==NULL)
{
o=new xyz111();
o->ch[]=o->ch[]=NULL;
o->value=x;
o->size=;
o->key=rand()%;
}
else
{
int d=o->cmp(x);
if(d==-) return;
insert(o->ch[d],x);
if(o->ch[d]->key>o->key) rorate(o,d^);
}
o->maintain();
}
int kth(xyz111* o,int k)
{
int l=;
if(o->ch[]!=NULL) l=o->ch[]->size;
if(l+==k) return o->value;
if(l+>k) return kth(o->ch[],k);
return kth(o->ch[],k-l-);
}
int rank(xyz111* o,int x)
{
if(o==NULL) return ;
int d=o->cmp(x),l=;
if(o->ch[]!=NULL) l=o->ch[]->size;
if(d==-) return l+;
if(d==) return rank(o->ch[],x);
return l++rank(o->ch[],x);
}
int main()
{
scanf("%d",&n);
int ans;
scanf("%d",&ans);
insert(root,ans);
for(int i=;i<=n;++i)
{
int x;
scanf("%d",&x);
int k=rank(root,x);
if(k==) ans+=kth(root,)-x;
else
if(k==root->size) ans+=x-kth(root,root->size);
else
ans+=min(x-kth(root,k),kth(root,k+)-x);
insert(root,x);
}
printf("%d",ans);
return ;
}

匈牙利算法

 #include<bits/stdc++.h>
using namespace std;
const int maxn=;
vector<int> g[maxn+];
bool v[maxn+];
int f[maxn+];
int n,m;
void addedge(int u,int v)
{
g[u].push_back(v);
g[v].push_back(u);
}
bool dfs(int k)
{
for(int i=;i<g[k].size();++i)
if(v[g[k][i]]==)
{
v[g[k][i]]=;
if(f[g[k][i]]==||dfs(f[g[k][i]]))
{
f[g[k][i]]=k;
f[k]=g[k][i];
return true;
}
}
return false;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=;i<=n+m;++i) g[i].clear();
for(int i=n+;i<=m+n;++i)
{
int x,y;
scanf("%d %d",&x,&y);
++x,++y;
addedge(i,x);
addedge(i,y);
}
memset(f,,sizeof(f));
int ans=;
for(int i=;i<=n+m;++i)
{
if(f[i]!=) continue;
memset(v,,sizeof(v));
if(dfs(i)) ++ans;
}
printf("%d",ans);
return ;
}

有向图强连通(两次DFS)

 #include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5,inf=1e9;
vector < int > g[maxn+],g1[maxn+],g2[maxn+];
bool v[maxn+];
int n,m,color[maxn+],t[maxn+],len,c,d[maxn+];
void dfs(int k)
{
v[k]=;
for(int i=;i<g[k].size();++i)
if(!v[g[k][i]]) dfs(g[k][i]);
++len;
t[len]=k;
}
void dfs1(int k)
{
v[k]=;
color[k]=c;
for(int i=;i<g1[k].size();++i)
if(!v[g1[k][i]]) dfs1(g1[k][i]);
}
bool check2(int a,int b)
{
if(a==b) return ;
for(int i=;i<g2[a].size();++i)
if(g2[a][i]==b) return ;
return ;
}
int main()
{ while(scanf("%d %d",&n,&m)!=EOF)
{
c=;
len=;
memset(d,,sizeof(d));
for(int i=;i<=n;++i) g[i].clear(),g1[i].clear(),g2[i].clear();
for(int i=;i<=m;++i)
{
int x,y;
scanf("%d %d",&x,&y);
g[x].push_back(y);
g1[y].push_back(x);
}
memset(v,,sizeof(v));
memset(t,,sizeof(t));
for(int i=;i<=n;++i) if(!v[i]) dfs(i);
memset(v,,sizeof(v));
for(int i=len;i>=;--i) if(!v[t[i]]) ++c,dfs1(t[i]);
for(int i=;i<=n;++i)
for(int j=;j<g[i].size();++j)
if(check2(color[i],color[g[i][j]]))
g2[color[i]].push_back(color[g[i][j]]),++d[color[i]];
int s=,x=;
for(int i=;i<=c;++i) if(d[i]==) ++s,x=i;
if(s>) printf("0\n");
else
{
int ans=;
for(int i=;i<=n;++i)
if(color[i]==x) ++ans;
printf("%d\n",ans);
}
}
return ;
}
/*bitset优化*/
void dfs(int k)
{
if(vis[k]==) return;
vis.reset(k);
bitset<maxn+> nx=vis&g[k];
int u=nx._Find_first();
while(u<=n)
{
dfs(u);
u=nx._Find_next(u);
}
a.push_back(k);
}
void dfs1(int k)
{
if(vis[k]==) return;
vis.reset(k);
bitset<maxn+> nx=vis&g1[k];
int u=nx._Find_first();
while(u<=n)
{
dfs1(u);
u=nx._Find_next(u);
}
}

无向图的点双联通分量

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,maxm=;
vector<int> g[maxn+],bcc[maxn+];
int dfstime[maxn+],low[maxn+],color[maxn+],head[maxn+];
bool p[maxn+][maxn+],map[maxn+][maxn+],flag;
int n,m,top,c,t;
bool ins[maxn+];
struct wjmzbmr
{
int u,v;
}s[maxm];
void tarjan(int k,int fa)
{
low[k]=dfstime[k]=++t;
for(int i=;i<g[k].size();++i)
{
int u=g[k][i];
if(u==fa) continue;
if(dfstime[u])
if(dfstime[u]<dfstime[k]) low[k]=min(low[k],dfstime[u]),s[++top]={k,u};
else;
else
{
s[++top]={k,u};
tarjan(u,k);
low[k]=min(low[k],low[u]);
if(low[u]>=dfstime[k])
{
++c;
while()
{
wjmzbmr e=s[top--];
if(color[e.u]!=c)
{
bcc[c].push_back(e.u);
color[e.u]=c;
}
if(color[e.v]!=c)
{
bcc[c].push_back(e.v);
color[e.v]=c;
}
if(e.u==k&&e.v==u) break;
}
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
while(!(n==&&m==))
{
for(int i=;i<=n;++i) g[i].clear(),bcc[i].clear();
memset(p,,sizeof(p));
for(int i=;i<=m;++i)
{
int x,y;
scanf("%d %d",&x,&y);
p[x][y]=p[y][x]=;
}
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
if(i!=j&&!p[i][j]) g[i].push_back(j);
memset(dfstime,,sizeof(dfstime));
memset(s,,sizeof(s));
memset(color,,sizeof(color));
top=c=t=;
for(int i=;i<=n;++i)
if(!dfstime[i]) tarjan(i,-);
scanf("%d %d",&n,&m);
}
return ;
}

无向图的边双联通分量

 #include<bits\stdc++.h>
using namespace std;
const int maxn=4e5;
struct wjmzbmr
{
int x,y,pos;
};
wjmzbmr e[*maxn+];
vector<int> g[maxn+];
int dfstime[maxn+],low[maxn+],s[maxn+],color[maxn+],num[maxn+];
int n,m,top,c,t,ans1=;
bool ins[maxn+];
void tarjan(int k,int fa)
{
low[k]=dfstime[k]=++t;
s[++top]=k;
ins[k]=;
for(int i=;i<g[k].size();++i)
{
int u=e[g[k][i]].y;
if(fa==u) continue;
if(!dfstime[u])
{
tarjan(u,k);
//if(low[u]>dfstime[k]) p[g[k][i]]=1; 判断此边是否为桥
low[k]=min(low[k],low[u]);
}
else
if(ins[u]) low[k]=min(low[k],low[u]);
}
if(dfstime[k]==low[k])
{
++c;
while()
{
int v=s[top--];
ins[v]=,color[v]=c,++num[c];
if(v==k) break;
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=;i<=n;++i) g[i].clear();
for(int i=;i<=m;++i)
{
int x,y;
scanf("%d %d",&x,&y);
g[x].push_back(*i-),g[y].push_back(*i);
e[*i-]={x,y,i},e[*i]={y,x,i};
}
memset(dfstime,,sizeof(dfstime));
for(int i=;i<=n;++i) low[i]=n+;
memset(color,,sizeof(color));
memset(num,,sizeof(num));
memset(s,,sizeof(s));
memset(ins,,sizeof(ins));
top=c=t=;
tarjan(,-);
return ;
}

求凸包

 #include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=;
struct wjmzbmr
{
int x,y;
bool operator < (const wjmzbmr& a) const
{
return (x<a.x)||(x==a.x&&y<a.y);
}
}a[maxn+];
int n,s[maxn+],q[maxn+],m=,len=;
int cross(int x1,int y1,int x2,int y2)
{
return (x1*y2-y1*x2);
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d %d",&a[i].x,&a[i].y);
sort(a+,a+n+);
m=;
s[]=,s[]=;
for(int i=;i<=n;++i)
{
while(m>=&&cross(a[s[m]].x-a[s[m-]].x,a[s[m]].y-a[s[m-]].y,a[i].x-a[s[m]].x,a[i].y-a[s[m]].y)<=) --m;
s[++m]=i;
}
s[++m]=n-;
int k=m;
for(int i=n-;i>=;--i)
{
while(m>=k&&cross(a[s[m]].x-a[s[m-]].x,a[s[m]].y-a[s[m-]].y,a[i].x-a[s[m]].x,a[i].y-a[s[m]].y)<=) --m;
s[++m]=i;
}
int ans=;
for(int i=;i<=m-;++i)
for(int j=i+;j<=m;++j)
if((a[s[i]].x-a[s[j]].x)*(a[s[i]].x-a[s[j]].x)+(a[s[i]].y-a[s[j]].y)*(a[s[i]].y-a[s[j]].y)>ans) ans=(a[s[i]].x-a[s[j]].x)*(a[s[i]].x-a[s[j]].x)+(a[s[i]].y-a[s[j]].y)*(a[s[i]].y-a[s[j]].y);
printf("%d",ans);
return ;
}

主席树求区间k小

 #include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=;
struct wjmzbmr
{
int l,r,ls,rs,sum;
}f[maxn*];
struct fotile96
{
int l,r,mid;
}stack[maxn+];
int a[maxn+],sorta[maxn+],root[maxn+],n,len=;
int build(int l,int r)
{
int k=++len;
f[k].l=l,f[k].r=r,f[k].ls=f[k].rs=f[k].sum=;
if(l==r) return len;
int mid=(l+r)>>;
f[k].ls=build(l,mid);
f[k].rs=build(mid+,r);
return k;
}
int change(int root,int x)
{
int k=++len;
f[k]=f[root],f[k].sum+=;
if(f[k].l==f[k].r) return k;
int mid=(f[k].l+f[k].r)>>;
if(x<=mid) f[k].ls=change(f[k].ls,x);else f[k].rs=change(f[k].rs,x);
return k;
}
int ask(int a,int b,int k)
{
if(f[b].l==f[b].r) return f[b].r;
int mid=f[f[b].ls].sum-f[f[a].ls].sum;
if(k<=mid) return ask(f[a].ls,f[b].ls,k);else return ask(f[a].rs,f[b].rs,k-mid);
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
for(int i=;i<=n;++i) sorta[i]=a[i];
sort(sorta+,sorta+n+);
int q=;
for(int i=;i<=n;++i) if(sorta[i]!=sorta[q]) sorta[++q]=sorta[i];
root[]=build(,q);
for(int i=;i<=n;++i)
{
int x=lower_bound(sorta+,sorta+q+,a[i])-sorta;
root[i]=change(root[i-],x);
}
len=;
stack[len].l=stack[len].r=,stack[len].mid=a[];
for(int i=;i<=n;++i)
{
++len;
stack[len].l=stack[len].r=i,stack[len].mid=a[i];
while (len>&&stack[len].mid<stack[len-].mid)
{
stack[len-].r=stack[len].r;
--len;
stack[len].mid=sorta[ask(root[stack[len].l-],root[stack[len].r],(stack[len].r-stack[len].l+)/+)];
}
}
int ans=;
for (int i=;i<=len;++i)
for (int j=stack[i].l;j<=stack[i].r;++j)
ans+=abs(a[j]-stack[i].mid);
printf("%d",ans);
return ;
}

主席舒求区间k小(带修改)

 //时间是O(nlog^2n)
//空间也是O(nlog^2n),不过可以采用地址回收
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=5e4;
vector<int> L,R;
int sorta[maxn*+],a[maxn*+],rk[maxn+];
int ch[maxn**+][],sum[maxn**+],root[maxn+];
int sz=,len=;
int n,m,T;
int lowbit(int x)
{
return x&(-x);
}
int change(int last,int l,int r,int x,int type)//type=1表示加上x,type=-1表示减去x
{
int k=++len;
ch[k][]=ch[last][],ch[k][]=ch[last][],sum[k]=sum[last]+type;
if(l==r) return k;
int mid=(l+r)>>;
if(x<=mid) ch[k][]=change(ch[last][],l,mid,x,type);else ch[k][]=change(ch[last][],mid+,r,x,type);
return k;
}
int query(int l,int r,int k)//询问[l,R]之间的第k小的值
{
if(l==r) return l;
int suml=,sumr=;
for(int i=;i<L.size();++i) suml+=sum[ch[L[i]][]];
for(int i=;i<R.size();++i) sumr+=sum[ch[R[i]][]];
int mid=(l+r)>>;
if(k<=sumr-suml)
{
for(int i=;i<L.size();++i) L[i]=ch[L[i]][];
for(int i=;i<R.size();++i) R[i]=ch[R[i]][];
return query(l,mid,k);
}
else
{
for(int i=;i<L.size();++i) L[i]=ch[L[i]][];
for(int i=;i<R.size();++i) R[i]=ch[R[i]][];
return query(mid+,r,k-(sumr-suml));
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i) scanf("%d",&a[i]),sorta[i]=a[i];
sort(sorta+,sorta+n+);
len=,sz=;
rk[]=sorta[];
for(int i=;i<=n;++i) if(sorta[i]!=sorta[i-]) sorta[++sz]=sorta[i],rk[sz]=sorta[i];//离散
memset(root,,sizeof(root));
for(int i=;i<=n;++i)
{
int id=lower_bound(sorta+,sorta+sz+,a[i])-sorta;
for(int j=i;j<=n;j+=lowbit(j))
root[j]=change(root[j],,sz,id,);//每个点自己建
}
while(m--)
{
char c=' ';
int x,y,k;
while(c!='Q'&&c!='C') c=getchar();
if(c=='C')
{
scanf("%d%d",&x,&y);
int id=lower_bound(sorta+,sorta+sz+,a[x])-sorta;
for(int i=x;i<=n;i+=lowbit(i)) root[i]=change(root[i],,sz,id,-);
a[x]=y;
id=lower_bound(sorta+,sorta+sz+,a[x])-sorta;
for(int i=x;i<=n;i+=lowbit(i)) root[i]=change(root[i],,sz,id,);
}
else
{
scanf("%d%d%d",&x,&y,&k);
L.clear(),R.clear();
for(int i=x-;i;i-=lowbit(i)) L.push_back(root[i]);
for(int i=y;i;i-=lowbit(i)) R.push_back(root[i]);
printf("%d\n",rk[query(,sz,k)]);
}
}
}
return ;
}

dinic

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,inf=1e9,maxm=;
struct Edge
{
int from,to,cap,flow;
}edge[maxm*+];;
vector <int> g[maxn+];
int step[maxn];//从源点到点x的距离
int iter[maxn];//定点x的第几条边开始有用
int n,m,S,T,len;
void addedge(int from,int to,int cap)
{
++len;
edge[len]={from,to,cap,};
g[from].push_back(len);
++len;
edge[len]={to,from,,};
g[to].push_back(len);
}
void bfs(int S)
{
memset(step,-,sizeof(step));
step[S]=;
queue<int> q;
q.push(S);
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=;i<g[v].size();++i)
{
Edge &e=edge[g[v][i]];
if(e.cap>e.flow&&step[e.to]<)
{
step[e.to]=step[v]+;
q.push(e.to);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t) return f;
for(int &i=iter[v];i<g[v].size();++i)//这里是引用,i++的同时iter也++,其实相当于上个的used,不过不用判断了
{
Edge &e=edge[g[v][i]];
if(e.cap>e.flow&&step[e.to]>step[v])
{
int d=dfs(e.to,t,min(e.cap-e.flow,f));
if(d>)
{
e.flow+=d;
edge[g[v][i]^].flow-=d;
return d;
}
}
}
return ;
}
int maxflow(int S,int T)
{
int flow=;
for(;;)
{
bfs(S);
if(step[T]<) return flow;
memset(iter,,sizeof(iter));
int f;
while((f=dfs(S,T,inf))>)
flow+=f;
}
}
int main()
{
scanf("%d%d",&n,&m);
S=,T=n+;
for(int i=;i<=T;++i) g[i].clear();
len=-;
for(int i=;i<=n;++i)
{
int x;
scanf("%d",&x);
if(x==) addedge(S,i,);else addedge(i,T,);
}
for(int i=;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v,);
addedge(v,u,);
}
printf("%d\n",maxflow(S,T));
return ;
}

最大费用最大流(可行流)

 #include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn=,maxm=,inf=1e7;
const double eps=1e-;
struct wjmzbmr
{
int from,to,cap,flow;
double cost;
}edge[*maxm];
vector<int> g[maxn+];
double d[maxn+];
int a[maxn+],b[maxn+],last[maxn+],f[maxn+];
int n,m,t,len,S,T;
bool v[maxn+];
void add(int from,int to,int cap,double cost)
{
edge[++len]=(wjmzbmr){from,to,cap,,cost},g[from].push_back(len);
edge[++len]=(wjmzbmr){to,from,,,-cost},g[to].push_back(len);
}
bool spfa(int S,int T,int &flow,double &cost)
{
for(int i=;i<=n+;++i) d[i]=(double)-inf,f[i]=inf;
memset(v,,sizeof(v));
d[S]=0.0,v[S]=,last[S]=,f[S]=inf;
queue<int> q;
while(!q.empty()) q.pop();
q.push(S);
while(!q.empty())
{
int u=q.front();
q.pop();
v[u]=;
for(int i=;i<g[u].size();++i)
{
wjmzbmr& e=edge[g[u][i]];
if(e.cap>e.flow&&(d[e.to]+eps<d[u]+e.cost))
{
d[e.to]=d[u]+e.cost;
last[e.to]=g[u][i];
f[e.to]=min(f[u],e.cap-e.flow);
if(!v[e.to])
{
q.push(e.to);
v[e.to]=;
}
}
}
}
if(d[T]==-inf) return false;
//if(d[T]*f[T]<0) return false;最大费用可行流
flow+=f[T];
cost+=d[T]*f[T];
int u=T;
while(u!=S)
{
edge[last[u]].flow+=f[T];
edge[last[u]^].flow-=f[T];
u=edge[last[u]].from;
}
return true;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
len=-;
for(int i=;i<=n;++i) g[i].clear();
for(int i=;i<=n;++i) scanf("%d %d",&a[i],&b[i]);
for(int i=;i<=m;++i)
{
int x,y,z;double p;
scanf("%d %d %d %lf",&x,&y,&z,&p);
p=log2(1.0-p);
if(z==) continue;
else
{
add(x,y,,);
add(x,y,z-,p);
}
}
S=,T=n+;
for(int i=;i<=n;++i)
{
if(a[i]-b[i]==) continue;
if(a[i]-b[i]>) add(S,i,a[i]-b[i],);
else add(i,T,b[i]-a[i],);
}
int flow=;double cost=0.0;
while(spfa(S,T,flow,cost)) ;
printf("%.2f\n",1.0-pow(2.0,cost));
}
return ;
}

高斯消元

 /*
n个未知数,m个方程
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
const double eps=1e-;
double a[maxn+][maxn+];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;++i)
for(int j=;j<=n+;++j)
scanf("%lf",&a[i][j]);
for(int i=;i<=n;++i)//枚举列
{
if(fabs(a[i][i]-0.0)<=eps)
{
int j;
bool flag=;
for(j=i+;j<=m;++j)
if(fabs(a[j][i]-0.0)>eps)
{
flag=;
break;
}
if(!flag) return *printf("Many solutions");//如果第i~m行的第i列都是0,那么多解
for(int k=;k<=n+;++k) swap(a[i][k],a[j][k]);
}
for(int j=;j<=n+;++j) if(i!=j)a[i][j]/=a[i][i];a[i][i]=1.0;
for(int j=;j<=m;++j)
if(j!=i)
{
for(int k=;k<=n+;++k) if(k!=i) a[j][k]-=a[i][k]*a[j][i];a[j][i]=0.0;
}
}
for(int i=n+;i<=m;++i)
if(fabs(a[i][n+]-0.0)>eps) return *printf("No solutions");//n+1~m这些方程应该所有变量都被消干净了,所以如果不为0,则说明无解
for(int i=;i<=n;++i) printf("%d\n",(int)(a[i][n+]+0.5));
return ;
}

求行列式

 const int maxn=;
ll a[maxn+][maxn+];
int turn,n;
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b) d=a,x=,y=;
else
{
++turn;
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
ll det(ll n)
{
//求行列式a[0..n-1][0..n-1]
ll tmp1[maxn+],tmp2[maxn+];
ll ans=;
for(int i=;i<n;++i)
{
for(int j=i+;j<n;++j)
if(a[j][i]!=)
{
ll A=a[i][i],B=a[j][i],d,x,y;
turn=;
gcd(A,B,d,x,y);
for(int k=;k<n;++k) tmp1[k]=a[i][k],tmp2[k]=a[j][k];
for(int k=;k<n;++k) a[i][k]=(x*tmp1[k]+y*tmp2[k])%mod;
A/=d,B/=d;
if(turn&) x=B,y=-A,ans=-ans%mod;else x=-B,y=A;
for(int k=;k<n;++k) a[j][k]=(x*tmp1[k]+y*tmp2[k])%mod;
}
ans=ans*a[i][i]%mod;
}
if(ans<) ans+=mod;
return ans;
}

splay维护数列问题

 #include<bits/stdc++.h>
using namespace std;
const int maxn=2e5,inf=1e9;
int pre[maxn+],ch[maxn+][],flip[maxn+],key[maxn+],sz[maxn+],mi[maxn+],add[maxn+];
int a[maxn+];
int n,root=,len=,m;
struct wjmzbmr
{
int num,id;
bool operator < (const wjmzbmr& x) const
{
return num<x.num||(num==x.num&&id<x.id);
}
}b[maxn+];
void update(int k)
{
int l=ch[k][],r=ch[k][];
sz[k]=+sz[l]+sz[r];
mi[k]=min(key[k],min(mi[l],mi[r]));
}
void pushdown(int k)
{
int& l=ch[k][];
int& r=ch[k][];
if(add[k])
{
if(l) add[l]+=add[k],mi[l]+=add[k],key[l]+=add[k];
if(r) add[r]+=add[k],mi[r]+=add[k],key[r]+=add[k];
add[k]=;
}
if(flip[k])
{
flip[k]=;
swap(l,r);
if(l) flip[l]^=;
if(r) flip[r]^=;
}
}
void rorate(int k,int d)
{
int f=pre[pre[k]],p=pre[k];
pushdown(p),pushdown(k);
ch[p][d^]=ch[k][d];
pre[ch[k][d]]=p;
ch[k][d]=p;
pre[k]=f;
pre[p]=k;
if(f) ch[f][ch[f][]==p]=k;else root=k;
update(p),update(k);
}
void splay(int x,int goal)
{
pushdown(x);
while(pre[x]!=goal)
{
pushdown(x);
if(pre[pre[x]]==goal) rorate(x,ch[pre[x]][]==x);
else
{
int d1=ch[pre[x]][]==x,d2=ch[pre[pre[x]]][]==pre[x];
if(d1==d2) rorate(pre[x],d2),rorate(x,d1);
else rorate(x,d1),rorate(x,d2);
}
}
update(x);
if(goal==) root=x;
}
int build(int l,int r,int fa)
{
if(l>r) return ;
if(l==r)
{
pre[l]=fa,ch[l][]=ch[l][]=,add[l]=flip[l]=,key[l]=mi[l]=a[l],sz[l]=;
return l;
}
int mid=(l+r)>>;
pre[mid]=fa,ch[mid][]=ch[mid][]=,add[mid]=flip[mid]=,key[mid]=mi[mid]=a[mid],sz[mid]=;
ch[mid][]=build(l,mid-,mid),ch[mid][]=build(mid+,r,mid);
update(mid);
return mid;
}
void find(int k,int goal)
{
int t=root;
while(true)
{
pushdown(t);
if(sz[ch[t][]]+==k) break;
if(k<=sz[ch[t][]]) t=ch[t][];else k-=sz[ch[t][]]+,t=ch[t][];
}
splay(t,goal);
}
void make(int l,int r,int c)//将区间[l,r]剪掉,接在新序列的第c位后面
{
find(l-,);
find(r+,root);
int u=ch[ch[root][]][];
find(sz[ch[root][]]++sz[u],ch[root][]);
u=ch[ch[root][]][];
ch[ch[root][]][]=;
update(ch[root][]),update(root);
find(c,);
ch[u][]=ch[root][],ch[root][]=u;
pre[ch[u][]]=u,pre[u]=root;
update(u),update(root);
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n+;++i) scanf("%d",&a[i]);
mi[]=key[]=inf;
root=build(,n+,);
len=n+;
scanf("%d",&m);
while(m--)
{
char s[];
int l,r,x;
scanf("%s",s);
if(s[]=='A')//[l,r]加上x
{
scanf("%d%d%d",&l,&r,&x);
++l,++r;
find(l-,);
find(r+,root);
int u=ch[ch[root][]][];
add[u]+=x,key[u]+=x,mi[u]+=x;
update(ch[root][]),update(root);
}
if(s[]=='R'&&s[]=='E')//[l,r]反转
{
scanf("%d%d",&l,&r);
++l,++r;
find(l-,);
find(r+,root);
int u=ch[ch[root][]][];
flip[u]^=;
}
if(s[]=='R'&&s[]=='O')//[l,r]循环右移x次
{
scanf("%d%d%d",&l,&r,&x);
++l,++r;
x%=r-l+;
make(l,r-x,x+l-);
}
if(s[]=='I')//在l后插入一个位置,初值为x
{
scanf("%d%d",&l,&x);
++l;
find(l,);
int u=ch[root][];
++len;
pre[len]=root,ch[len][]=ch[len][]=,add[len]=flip[len]=,key[len]=mi[len]=x,sz[len]=;
ch[root][]=len;
ch[len][]=u;
pre[u]=len;
update(len),update(root);
}
if(s[]=='D')//删除第i个位置
{
scanf("%d",&l);
++l;
find(l-,);
find(l+,root);
ch[ch[root][]][]=;
update(ch[root][]),update(root);
}
if(s[]=='M')//求[l,r]最小值
{
scanf("%d%d",&l,&r);
++l,++r;
find(l-,);
find(r+,root);
printf("%d\n",mi[ch[ch[root][]][]]);
}
}
return ;
}

LCT

 struct LCT
{
int ch[maxn+][],fa[maxn+],flip[maxn+];
int top;
int q[maxn+];
int mx[maxn+];
int s1[maxn+],s3[maxn+],sz[maxn+];//sz 实际子树大小 s1 指向某个点的非偏爱子树的大小和 s3 splay内子树中每个点的s1的和
void init()
{
for(int i=;i<=n;++i) mx[i]=i,sz[i]=,s3[i]=s1[i]=flip[i]=fa[i]=ch[i][]=ch[i][]=;
}
bool isroot(int x)
{
return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;
}
void update(int x)
{
int l=ch[x][],r=ch[x][];
mx[x]=x;
if(val[mx[l]]>val[mx[x]])mx[x]=mx[l];
if(val[mx[r]]>val[mx[x]])mx[x]=mx[r];
sz[x]=s3[r]+s1[x]+;
s3[x]=s3[l]+s3[r]+s1[x]+;
}
void pushdown(int x)
{
int l=ch[x][],r=ch[x][];
if(flip[x])
{
flip[x]^=;flip[l]^=;flip[r]^=;
swap(ch[x][],ch[x][]);
update(x);
}
}
void rotate(int &x)
{
int y=fa[x],z=fa[y],l,r;
if(ch[y][]==x) l=;
else l=;
r=l^;
if(!isroot(y))
{
if(ch[z][]==y) ch[z][]=x;
else ch[z][]=x;
}
fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
ch[y][l]=ch[x][r];ch[x][r]=y;
update(y);update(x);
}
void splay(int &x)
{
top=;
q[++top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(ch[y][]==x^ch[z][]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
for(int t=;x;t=x,x=fa[x])
{
splay(x);
s1[x]+=s3[ch[x][]];
ch[x][]=t;
s1[x]-=s3[t];
update(x);
}
}
void makeroot(int x)
{
access(x);splay(x);flip[x]^=;
pushdown(x);
}
bool linked(int x,int y)
{
//判断点x和点y是否在一个连通块中
makeroot(x);access(y);splay(y);
return x==y||fa[x];
}
void link(int x,int y)
{
makeroot(x);fa[x]=y;
access(y),splay(y),s1[y]+=s3[x];
update(y);
}
void cut(int x,int y)
{
makeroot(x);access(y);splay(y);
ch[y][]=fa[x]=;
sz[y]-=s3[x];
s3[y]-=s3[x];
update(y);
}
int findfather(int root,int x)
{
//返回实际树上以root为根,x的父亲
makeroot(root);
access(x),splay(x);
pushdown(x);
int fa=ch[x][];
while(true)
{
pushdown(fa);
if(!ch[fa][]) break;
fa=ch[fa][];
}
return fa; }
int querymax(int x,int y)
{
makeroot(x);access(y);splay(y);
return mx[y];
}
}lct;

倍增求LCA

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,q,cnt;
int deep[],head[],dis[],fa[][];
bool vis[];
struct data{int to,next,v;}e[];
void ins(int u,int v,int w)
{e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,w);}
void dfs(int x)
{
vis[x]=;
for(int i=;i<=;i++)
{
if(deep[x]<(<<i))break;
fa[x][i]=fa[fa[x][i-]][i-];
}
for(int i=head[x];i;i=e[i].next)
{
if(vis[e[i].to])continue;
deep[e[i].to]=deep[x]+;
dis[e[i].to]=dis[x]+e[i].v;
fa[e[i].to][]=x;
dfs(e[i].to);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
int d=deep[x]-deep[y];
for(int i=;i<=;i++)
if((<<i)&d)x=fa[x][i];
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])
{x=fa[x][i];y=fa[y][i];}
if(x==y)return x;
else return fa[x][];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
insert(u,v,w);
}
dfs();
for(int i=;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",dis[x]+dis[y]-*dis[lca(x,y)]);
}
return ;

FFT

 #include<bits/stdc++.h>
using namespace std;
const int maxn=;
const double pi=acos(-1.0);
int l,m,n,num;
int a[maxn+],b[maxn+];
struct wjmzbmr
{
double r,i;
wjmzbmr(double real=0.0,double image=0.0){r=real;i=image;}
wjmzbmr operator + (const wjmzbmr o)
{
return wjmzbmr(r+o.r,i+o.i);
}
wjmzbmr operator - (const wjmzbmr o)
{
return wjmzbmr(r-o.r,i-o.i);
}
wjmzbmr operator * (const wjmzbmr o)
{
return wjmzbmr(r*o.r-i*o.i,r*o.i+i*o.r);
}
};
wjmzbmr x1[maxn+],x2[maxn+];
void brc(wjmzbmr *y,int l)
{
for(int i=,j=l/;i<l-;i++)
{
if(i<j) swap(y[i],y[j]);
int k=l/;
while(j>=k)j-=k,k/=;
if(j<k) j+=k;
}
}
void fft(wjmzbmr *y,int l,double on)
{
wjmzbmr u,t;
brc(y,l);
for(int h=;h<=l;h<<=)
{
wjmzbmr wn(cos(on**pi/h),sin(on**pi/h));
for(int j=;j<l;j+=h)
{
wjmzbmr w(,);
for(int k=j;k<j+h/;k++)
{
u=y[k];
t=w*y[k+h/];
y[k]=u+t;
y[k+h/]=u-t;
w=w*wn;
}
}
}
if(on==-)for(int i=;i<l;i++) y[i].r/=l;
}
void init(int *a,int n,wjmzbmr *x1,int *b,int m,wjmzbmr *x2)
{
/*将a[0]~a[n-1]放到x1中,将b[0]~b[m-1]放到x2中*/
l=;
while(l<max(n,m)*) l<<=;
for(int i=;i<n;++i)
{
x1[i].r=a[i];
x1[i].i=0.0;
}
for(int i=n;i<l;++i)x1[i].r=x1[i].i=0.0;
for(int i=;i<m;++i)
{
x2[i].r=b[i];
x2[i].i=0.0;
}
for(int i=m;i<l;i++) x2[i].r=x2[i].i=0.0;
}
int main()
{
scanf("%d %d",&n,&m);
++n,++m;
for(int i=;i<n;++i) scanf("%d",&a[i]);
for(int i=;i<m;++i) scanf("%d",&b[i]);
init(a,n,x1,b,m,x2);
fft(x1,l,);
fft(x2,l,);
for(int i=;i<l;++i) x1[i]=x1[i]*x2[i];
fft(x1,l,-);
for(int i=;i<n+m-;++i) printf("%lld ",(long long)(x1[i].r+0.5));
return ;
}

FWT

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,mod=1e9+,rev=(mod+)>>;
int a[maxn+],b[maxn+];
long long fc[maxn*maxn];
int T,n,m;
void fwt(int *a,int n)
{
for(int d=;d<n;d<<=)
for(int m=d<<,i=;i<n;i+=m)
for(int j=;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=;d<n;d<<=)
for(int m=d<<,i=;i<n;i+=m)
for(int j=;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)//下标0..n-1的数组a和b求异或卷积,O(nlogn),返回值在a中
{
fwt(a,n);
fwt(b,n);
for(int i=;i<n;++i) a[i]=1LL*a[i]*b[i]%mod;
ufwt(a,n);
}
int main()
{
fc[]=;
for(int i=;i<=;++i) fc[i]=fc[i-]*i%mod;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(a,,sizeof(a));
memset(b,,sizeof(b));
for(int i=;i<=n;++i) a[i]=;
for(int i=;i<=m;++i) b[i]=;
solve(a,b,maxn);
long long ans=;
for(int i=;i<maxn;++i) ans=ans*fc[a[i]]%mod;
printf("%lld\n",ans);
}
return ;
}

NTT

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=*;
//const long long P=50000000001507329LL; // 190734863287 * 2 ^ 18 + 1
//const int P=1004535809; // 479 * 2 ^ 21 + 1
const ll mod=; // 119 * 2 ^ 23 + 1
const ll G=; ll len=;
ll pw[maxn+],pwinv[maxn+];
ll A[maxn+],B[maxn+];
ll f[maxn+];
int n,m; ll Pow(ll a,ll b,ll mod)
{
ll ans=;
while(b)
{
if(b&) ans=ans*a%mod;
a=a*a%mod;
b>>=;
}
return ans;
}
ll Inv(ll x)
{
return Pow(x,mod-,mod);
}
void Init()
{
ll inv=Inv(G);
for (int i=;i<=maxn;i<<=)
{
pw[i]=Pow(G,(mod-)/i,mod);
pwinv[i]=Pow(inv,(mod-)/i,mod);
}
}
void rader(ll *a)
{
for(int i=,j=;i<len;i++)
{
if(i>j) swap(a[i],a[j]);
int k=len;
do{k>>=;j^=k;}while(j<k);
}
}
void ntt(ll *a,int f)
{
rader(a);
for(int i=;i<=len;i<<=)
{
int m=i>>;
for(int j=;j<len;j+=i)
{
ll w=,wn=pw[i];
if(f==-) wn=pwinv[i];
for(int k=;k<m;k++)
{
ll x=a[j+k+m]*w%mod;
a[j+k+m]=(a[j+k]-x+mod)%mod;
a[j+k]=(a[j+k]+x)%mod;
w=w*wn%mod;
}
}
}
if(f==-)
{
ll inv=Inv(len);
for(int i=;i<len;i++) a[i]=a[i]*inv%mod;
}
}
void con(ll *A,int n,ll *B,int m)
{
/*A[0..n-1]与B[0..m-1]卷积*/
for(len=;len<max(n,m);len<<=);
len<<=;
for(int i=n;i<len;++i) A[i]=;
for(int i=m;i<len;++i) B[i]=;
ntt(A,);
ntt(B,);
for(int i=;i<len;++i) A[i]=A[i]*B[i]%mod;
ntt(A,-);
}
int main()
{
Init();
con(A,n,B,m);
return ;
}

Kdtree

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,inf=1e9;
int n,m,cur,ans,root;
int x[maxn+],y[maxn+];
struct P
{
int mn[],mx[],d[],lch,rch;
int& operator[](int x) {return d[x];}
friend bool operator<(P x,P y) {return x[cur]<y[cur];}
friend int dis(P x,P y) {return abs(x[]-y[])+abs(x[]-y[]);}
}p[maxn+];
struct kdtree
{
P t[*maxn+],T;
int ans;
void update(int k)
{
int l=t[k].lch,r=t[k].rch;
for (int i=;i<;i++)
{
t[k].mn[i]=t[k].mx[i]=t[k][i];
if(l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]);
if(r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]);
if(l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]);
if(r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]);
}
}
int build(int l,int r,int now)
{
cur=now;
int mid=(l+r)/;
nth_element(p+l,p+mid,p+r+);
t[mid]=p[mid];
for(int i=;i<;i++) t[mid].mx[i]=t[mid].mn[i]=t[mid][i];
if(l<mid) t[mid].lch=build(l,mid-,now^);
if(r>mid) t[mid].rch=build(mid+,r,now^);
update(mid);
return mid;
}
void insert(int k,int now)
{
if(T[now]<t[k][now])
{
if(t[k].lch) insert(t[k].lch,now^);
else
{
t[k].lch=++n;
t[n]=T;
for(int i=;i<;++i) t[n].mx[i]=t[n].mn[i]=t[n][i];
}
}
else
{
if(t[k].rch) insert(t[k].rch,now^);
else
{
t[k].rch=++n;
t[n]=T;
for(int i=;i<;++i) t[n].mx[i]=t[n].mn[i]=t[n][i];
}
}
update(k);
}
void ins(int x,int y)
{
T[]=x,T[]=y;
T.lch=T.rch=;
insert(root,);
}
int getmn(P x)
{
int ans=;
for(int i=;i<;i++)
{
ans+=max(T[i]-x.mx[i],);
ans+=max(x.mn[i]-T[i],);
}
return ans;
}//估价函数,注意如果是欧几里得距离辣么估价函数要修改
int getmx(P x)
{
int ans=;
for(int i=;i<;i++) ans+=max(abs(T[i]-x.mn[i]),abs(T[i]-x.mx[i]));
return ans;
}
void querymx(int k)
{
ans=max(ans,dis(t[k],T));
int l=t[k].lch,r=t[k].rch,dl=-inf,dr=-inf;
if (l) dl=getmx(t[l]);
if (r) dr=getmx(t[r]);
if (dl>dr)
{
if (dl>ans) querymx(l);
if (dr>ans) querymx(r);
}
else
{
if (dr>ans) querymx(r);
if (dl>ans) querymx(l);
}
}
void querymn(int k)
{
//if(dis(t[k],T)) ans=min(ans,dis(t[k],T));
ans=min(ans,dis(t[k],T));
int l=t[k].lch,r=t[k].rch,dl=inf,dr=inf;
if(l) dl=getmn(t[l]);
if(r) dr=getmn(t[r]);
if (dl<dr)
{
if (dl<ans) querymn(l);
if (dr<ans) querymn(r);
}
else
{
if (dr<ans) querymn(r);
if (dl<ans) querymn(l);
}
}
int query(int f,int x,int y)
{
T[]=x,T[]=y;
T.lch=T.rch=;
if (f==) ans=-inf,querymx(root);
else
ans=inf,querymn(root);
return ans;
}
}kdtree;
int main()
{ scanf("%d %d",&n,&m);
for(int i=;i<=n;++i)
{
scanf("%d%d",&x[i],&y[i]);
p[i][]=x[i],p[i][]=y[i];
}
root=kdtree.build(,n,);
for(int i=;i<=m;++i)
{
int t,x,y;
scanf("%d %d %d",&t,&x,&y);
if(t==) kdtree.ins(x,y);
if(t==) printf("%d\n",kdtree.query(,x,y));
}
return ;
}

Kdtree套替罪羊

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,inf=1e9;
int n,m,cur,ans,root;
int x[maxn+],y[maxn+];
struct P
{
int mn[],mx[],d[],lch,rch,sz;
int& operator[](int x) {return d[x];}
friend bool operator<(P x,P y) {return x[cur]<y[cur];}
friend int dis(P x,P y) {return abs(x[]-y[])+abs(x[]-y[]);}
}p[maxn*+];
namespace kdtree
{
const double alpha=0.75;
P t[*maxn+],T;
int id[maxn+];
int ans,len,tot;
bool cmp(const int x,const int y)
{
return p[x][cur]<p[y][cur];
}
void update(int k)
{
int l=t[k].lch,r=t[k].rch;
t[k].sz=t[t[k].lch].sz+t[t[k].rch].sz+;
for (int i=;i<;i++)
{
t[k].mn[i]=t[k].mx[i]=t[k][i];
if(l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]);
if(r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]);
if(l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]);
if(r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]);
}
}
int build(int l,int r,int now)
{
if(l>r) return ;
cur=now;
int mid=(l+r)/;
nth_element(id+l,id+mid,id+r+,cmp);
int k=id[mid];
t[k]=p[k];
t[k].sz=,t[k].lch=t[k].rch=;
for(int i=;i<;i++) t[k].mx[i]=t[k].mn[i]=t[k][i];
if(l<mid) t[k].lch=build(l,mid-,now^);
if(r>mid) t[k].rch=build(mid+,r,now^);
update(k);
return k;
}
void getid(int k)
{
id[++tot]=k;
p[k]=t[k];
if(t[k].lch) getid(t[k].lch);
if(t[k].rch) getid(t[k].rch);
}
int rebuild(int k,int now)
{
tot=;
getid(k);
return build(,tot,now);
}
int insert(int k,int now)
{
if(T[now]<t[k][now])
{
if(t[k].lch) t[k].lch=insert(t[k].lch,now^);
else
{
t[k].lch=++len;
t[len]=T;
for(int i=;i<;++i) t[len].mx[i]=t[len].mn[i]=t[len][i];
}
}
else
{
if(t[k].rch) t[k].rch=insert(t[k].rch,now^);
else
{
t[k].rch=++len;
t[len]=T;
for(int i=;i<;++i) t[len].mx[i]=t[len].mn[i]=t[len][i];
}
}
update(k);
if(t[k].sz*alpha+<max(t[t[k].lch].sz,t[t[k].rch].sz)) k=rebuild(k,now);
return k;
}
void ins(int x,int y)
{
T[]=x,T[]=y;
T.sz=;
T.lch=T.rch=;
if(root==)
{
len=;
t[len]=T;
update(len);
root=len;
return;
}
root=insert(root,);
}
int getmn(P x)
{
int ans=;
for(int i=;i<;i++)
{
ans+=max(T[i]-x.mx[i],);
ans+=max(x.mn[i]-T[i],);
}
return ans;
}//估价函数,注意如果是欧几里得距离辣么估价函数要修改
int getmx(P x)
{
int ans=;
for(int i=;i<;i++) ans+=max(abs(T[i]-x.mn[i]),abs(T[i]-x.mx[i]));
return ans;
}
void querymx(int k)
{
ans=max(ans,dis(t[k],T));
int l=t[k].lch,r=t[k].rch,dl=-inf,dr=-inf;
if (l) dl=getmx(t[l]);
if (r) dr=getmx(t[r]);
if (dl>dr)
{
if (dl>ans) querymx(l);
if (dr>ans) querymx(r);
}
else
{
if (dr>ans) querymx(r);
if (dl>ans) querymx(l);
}
}
void querymn(int k)
{
//if(dis(t[k],T)) ans=min(ans,dis(t[k],T));
ans=min(ans,dis(t[k],T));
int l=t[k].lch,r=t[k].rch,dl=inf,dr=inf;
if(l) dl=getmn(t[l]);
if(r) dr=getmn(t[r]);
if (dl<dr)
{
if (dl<ans) querymn(l);
if (dr<ans) querymn(r);
}
else
{
if (dr<ans) querymn(r);
if (dl<ans) querymn(l);
}
}
int query(int f,int x,int y)
{
T[]=x,T[]=y;
T.lch=T.rch=;
if (f==) ans=-inf,querymx(root);
else
ans=inf,querymn(root);
return ans;
}
}
int main()
{
read(n);
read(m);
for(int i=;i<=n;++i)
{
read(x[i]);
read(y[i]);
p[i][]=x[i],p[i][]=y[i];
}
kdtree::len=n;
for(int i=;i<=n;++i) kdtree::id[i]=i;
root=kdtree::build(,n,);
for(int i=;i<=m;++i)
{
int t,x,y;
read(t);
read(x);
read(y);
if(t==) kdtree::ins(x,y);
if(t==) printf("%d\n",kdtree::query(,x,y));
}
return ;
}

左偏树

 //APIO2012 dispatching
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
vector<int> g[maxn+];
long long cost[maxn+],lead[maxn+],sum[maxn+],num[maxn+];
int l[maxn+],r[maxn+],dist[maxn+];
int n,m,root;
long long ans=;
int merge(int u,int v)//左偏树核心操作——merge:合并两个左偏树
{
if(!u) return v;
if(!v) return u;
if(cost[u]<cost[v]) swap(u,v);//此处是大根堆
r[u]=merge(r[u],v);
if(dist[r[u]]>dist[l[u]]) swap(l[u],r[u]);//时刻保证dist(l)>=dist(r)
if(r[u]) dist[u]=dist[r[u]]+;else dist[u]=;//更新dist数组
num[u]=num[l[u]]+num[r[u]]+;
sum[u]=sum[l[u]]+sum[r[u]]+cost[u];//维护节点信息
return u;
}
int del(int u)
{
return merge(l[u],r[u]);//删除操作就是去掉根节点,merge左右儿子
}
int dfs(int k)
{
int u=k;
num[u]=,sum[u]=cost[u];
while(sum[u]>m) u=del(u);
for(int i=;i<g[k].size();++i)
{
int v=dfs(g[k][i]);
u=merge(u,v);
while(sum[u]>m) u=del(u);
}
ans=max(ans,lead[k]*num[u]);
return u;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i) g[i].clear();
for(int i=;i<=n;++i)
{
int x;
scanf("%d%d%d",&x,&cost[i],&lead[i]);
if(lead[i]==) root=i;
g[x].push_back(i);
}
memset(l,,sizeof(l));
memset(r,,sizeof(r));
memset(dist,,sizeof(dist));
memset(sum,,sizeof(sum));
memset(num,,sizeof(num));
dfs();
printf("%lld",ans);
return ;
}

莫比乌斯反演(筛积性函数+分块求和)

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int mu[maxn+],prime[maxn+],sum[maxn+];
bool f[maxn+];
int a,b,c,d,k;
long long solve(int n,int m)
{
if(n>m) swap(n,m);
long long ans=;
for(int i=,la=;i<=n;i=la+)
{
la=min(n/(n/i),m/(m/i));
ans+=(long long)(sum[la]-sum[i-])*(n/i)*(m/i);
}//对于n/i * m/i 采用分块求和的根号n+根号m的做法
return ans;
}
int main()
{
mu[]=;
memset(f,,sizeof(f));
f[]=;
for(int i=;i<=maxn;++i)
{
if(!f[i])
{
prime[++prime[]]=i;
mu[i]=-;
}
for(int j=;j<=prime[];++j)
{
if(i*prime[j]>maxn) break;
f[i*prime[j]]=;
if(i%prime[j]==)
{
mu[i*prime[j]]=;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}//筛积性函数
memset(sum,,sizeof(sum));
sum[]=mu[];
for(int i=;i<=maxn;++i) sum[i]=sum[i-]+mu[i];
int T;
scanf("%d",&T);
for(int cas=;cas<=T;++cas)
{
printf("Case %d: ",cas);
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==) printf("0\n");else
{
long long ans=solve(b/k,d/k)-solve((a-)/k,d/k)-solve(b/k,(c-)/k)+solve((a-)/k,(c-)/k);
a=max(a,c),b=min(b,d);
long long ans1=solve(b/k,b/k)-solve((a-)/k,b/k)-solve(b/k,(a-)/k)+solve((a-)/k,(a-)/k);
printf("%lld\n",ans-ans1/);
}
}
return ;
}

插头dp(最小表示法实现)

 /*
Ural 1519
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=,maxs=1e6,mod=;
struct wjmzbmr
{
vector<long long> hash[mod];
vector<int> num[mod];//num记录状态的编号
int len;
long long f[maxs],state[maxs];//f存的是该编号状态的dp值,state存的是该编号状态的数字
void init()
{
len=;
for(int i=;i<mod;++i) hash[i].clear(),num[i].clear();
}
void push(long long s,long long x)//把s状态的dp值加上x
{
int v=s%mod;
for(int i=;i<hash[v].size();++i)
if(hash[v][i]==s)
{
f[num[v][i]]+=x;
return;
}
++len;
hash[v].push_back(s);
num[v].push_back(len);
state[len]=s,f[len]=x;
}
}Hash[];
int maze[maxn+][maxn+];
char s[maxn+];
int code[maxn+];
int n,m,cur,ex=,ey=;
void decode(int *code,long long s)//解码,将状态s存到数组中,此题是8进制
{
for(int i=m;i>=;--i)
{
code[i]=s&;
s>>=;
}
}
long long encode(int *code)//编码,顺带用最小表示法更新标号
{
int color[maxn+],cnt=;
long long s=;
memset(color,-,sizeof(color));
color[]=;
for(int i=;i<=m;++i)
{
if(color[code[i]]==-) color[code[i]]=++cnt;
code[i]=color[code[i]];
s<<=;
s|=code[i];
}
return s;
}
void shift(int *code)//当轮廓线移到最后一列的时候需要特殊处理
{
for(int i=m;i>;--i) code[i]=code[i-];
code[]=;
}
void dpblank(int x,int y)
{
int left,up;
for(int i=;i<=Hash[cur].len;++i)
{
decode(code,Hash[cur].state[i]);
left=code[y-],up=code[y];
if(left&&up)//第一种情况,left和up都存在,(i,j)的作用是合并两个连通分量
{
if(left==up)//此题的特殊情况,连成一个整环只允许在最后一个非障碍格子
{
if(x==ex&&y==ey)
{
code[y]=code[y-]=;
if(y==m) shift(code);
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
}
else//合并两个连通分量
{
for(int i=;i<=m;++i)
if(code[i]==up) code[i]=left;
code[y]=code[y-]=;
if(y==m) shift(code);
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
}
else
if(left||up)//枚举(i,j)放右插头还是下插头
{
int t;
if(left) t=left;else t=up;
if(maze[x][y+])
{
code[y-]=,code[y]=t;
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
if(maze[x+][y])
{
code[y-]=t,code[y]=;
if(y==m) shift(code);
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
}
else
if(maze[x+][y]&&maze[x][y+])//该格子没有左插头也没有上插头,此题自己不能为空,所以它只有自己成一个新连通分量
{
code[y-]=code[y]=;//只需要填一个没有出现过的数即可,在最小表示法的时候会修正这个值
if(y==m) shift(code);
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
}
}
void dpblock(int x,int y)
{
for(int i=;i<=Hash[cur].len;++i)//当(x,y)是障碍格子的时候,肯定没有下插头、右插头
{
decode(code,Hash[cur].state[i]);
code[y-]=code[y]=;
if(y==m) shift(code);
Hash[cur^].push(encode(code),Hash[cur].f[i]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
{
scanf("%s",s+);
for(int j=;j<=m;++j)
if(s[j]=='.') maze[i][j]=,ex=i,ey=j;
}
Hash[cur=].init();
Hash[cur].push(,);
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
Hash[cur^].init();
if(maze[i][j]) dpblank(i,j);else dpblock(i,j);
cur^=;
}
long long ans=;
for(int i=;i<=Hash[cur].len;++i) ans+=Hash[cur].f[i];//最后的cur中存的状态都是能转移到的合法状态
printf("%lld\n",ans);
return ;
}

SAM(后缀自动机)

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e6;
char s[maxn+];
int sz=,len,last=;
int maxlen[*maxn+],minlen[*maxn+],trans[*maxn+][],slink[*maxn+],endpos[*maxn+],d[maxn*+];
long long ans[maxn*+];
int suf[maxn+];
int g[maxn+][];
bool p[maxn*+];
bool vis[maxn*+];
queue<int> q;
int build(int _maxlen,int _minlen,int* _trans,int _slink)
{
maxlen[++sz]=_maxlen;
minlen[sz]=_minlen;
for(int i=;i<;++i)
if(_trans==NULL) trans[sz][i]=-;else trans[sz][i]=_trans[i];
slink[sz]=_slink;
++d[_slink];
return sz;
}
int add(char ch,int u)
{
int c=ch-'a';
int z=build(maxlen[u]+,-,NULL,-);
p[z]=;
int v=u;
while(v!=-&&trans[v][c]==-) trans[v][c]=z,v=slink[v];
if(v==-)//最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移
{
minlen[z]=;
slink[z]=;
++d[];
return z;
}
int x=trans[v][c];
if(maxlen[v]+==maxlen[x])//较简单的情况,不用拆分x
{
minlen[z]=maxlen[x]+;
slink[z]=x;
++d[x];
return z;
}
int y=build(maxlen[v]+,-,trans[x],slink[x]); //最复杂的情况,拆分x,y表示<=maxlen[v]+1的那段
slink[y]=slink[x];
--d[slink[x]];
minlen[x]=maxlen[y]+;
slink[x]=y;
++d[y];
minlen[z]=maxlen[y]+;
slink[z]=y;
++d[y];
int w=v;
while(w!=-&&trans[w][c]==x) trans[w][c]=y,w=slink[w];
minlen[y]=maxlen[slink[y]]+;
return z;
}
void addedge(int u,int v,int w)
{
g[u][w]=v;
}
void goup(int k,int start,int step)
{
if(k==||vis[k]) return;
vis[k]=;
int father=slink[k];
step-=maxlen[k]-minlen[k]+;
addedge(father,k,s[start+step]-'a');
goup(father,start,step);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s);
len=strlen(s);
for(int i=;i<=*len;++i)
{
for(int j=;j<;++j) trans[i][j]=-;
slink[i]=-;
maxlen[i]=minlen[i]=;
memset(g[i],,sizeof(g[i]));
suf[i]=-;
//memset(limit[i],0,sizeof(limit[i]));
//dp[i]=0;
}
for(int i=;i<;++i) trans[][i]=slink[]=-;
maxlen[]=minlen[]=;
sz=;
last=;
for(int i=;i<len;++i)
{
last=add(s[i],last);//后缀树要倒过来建
suf[last]=i;
}
memset(endpos,,sizeof(endpos));
while(!q.empty()) q.pop();
for(int i=;i<=sz;++i) if(d[i]==) q.push(i); for(int i=;i<=sz;++i) vis[i]=;
for(int i=;i<=sz;++i)
if(suf[i]!=-) goup(i,suf[i],len-suf[i]); while(!q.empty())
{
int u=q.front();
q.pop();
if(p[u]) ++endpos[u];
endpos[slink[u]]+=endpos[u];
if(--d[slink[u]]==&&slink[u]!=) q.push(slink[u]);
}
memset(ans,,sizeof(ans));
for(int i=;i<=sz;++i) ans[maxlen[i]]=max(ans[maxlen[i]],(long long)endpos[i]);
for(int i=len-;i>=;--i) ans[i]=max(ans[i],ans[i+]);
for(int i=;i<=len;++i) printf("%lld\n",ans[i]);
}
return ;
}

图的遍历(非递归)

 void dfs(int k,int last)
{
/* L[k]=++t;
deep[k]=deep[last]+1;
fa[k][0]=last;
for(int i=0;i<g[k].size();++i)
if(g[k][i]!=last) dfs(g[k][i],k);
R[k]=t;*/
while(!s.empty()) s.pop();
memset(head,,sizeof(head));//head[i]表示第i个点当前遍历到了第几个相邻点
s.push();
s.push();
while(s.size()>)
{
int k=s.top();
s.pop();
int last=s.top();
s.push(k);
if(!head[k])
{
L[k]=++t;
deep[k]=deep[last]+;
fa[k][]=last;
}
if(head[k]<g[k].size())
if(g[k][head[k]]==last) ++head[k];
if(head[k]==g[k].size())
{
R[k]=t;
s.pop();
}
else
s.push(g[k][head[k]++]);
}
}

cdq分治模板(三维偏序)

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
struct wjmzbmr
{
int x,y,z,id;
};
wjmzbmr a[maxn+],p[maxn+];
bool cmp(wjmzbmr a,wjmzbmr b)
{
if(a.x!=b.x) return a.x<b.x;
if(a.y!=b.y) return a.y<b.y;
return a.z<b.z;
}
bool cmp2(wjmzbmr a,wjmzbmr b)
{
if(a.y!=b.y) return a.y<b.y;
return a.z<b.z;
}
int c[maxn+],ans[maxn+];
int n,maxz;
int lowbit(int x)
{
return x&(-x);
}
void add(int k,int num)
{
for(int i=k;i<=maxz;i+=lowbit(i)) c[i]+=num;
}
int query(int k)
{
int ans=;
for(int i=k;i;i-=lowbit(i)) ans+=c[i];
return ans;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>;
cdq(l,mid);
for(int i=l;i<=r;++i) p[i]=a[i];
//cdq(mid+1,r);
sort(p+l,p+mid+,cmp2);
sort(p+mid+,p+r+,cmp2);
int i=l;
for(int j=mid+;j<=r;++j)
{
while(i<=mid&&p[i].y<=p[j].y) add(p[i].z,),++i;
ans[p[j].id]+=query(p[j].z);
}
for(int j=l;j<i;++j) add(p[j].z,-);
cdq(mid+,r);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
maxz=;
for(int i=;i<=n;++i) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].id=i,maxz=max(maxz,a[i].z);
sort(a+,a+n+,cmp);
memset(c,,sizeof(c));
memset(ans,,sizeof(ans));
cdq(,n);
for(int i=n-;i>=;--i)
if(a[i].x==a[i+].x&&a[i].y==a[i+].y&&a[i].z==a[i+].z) ans[a[i].id]=ans[a[i+].id];
for(int i=;i<=n;++i) printf("%d\n",ans[i]);
}
return ;
}

优先队列

 struct priorityqueue
{
int num[maxn+],t[maxn+];//num表示数字,t表示时间
int l,r;
void init()
{
l=;
r=;
}
void push(int nu,int tu)//插入一个数字为nu,时间为tu的元素
{
while(r>=l&&num[r]>=nu) --r;
++r;
num[r]=nu,t[r]=tu;
}
void pop(int tu)//删除时间<tu的元素
{
while(l<=r&&t[l]<tu) ++l;
}
int getmin()//得到最小值
{
if(l>r) return inf;
else
return num[l];
}
};

手写bitset

 struct Bitset
{
/*32位压成一个unsigned int,最多压8个*/
unsigned int a[];
void clear()
{
for(int i=;i<;++i) a[i]=;
}
void set(int x)
{
/*第x位置1*/
a[x>>]|=1U<<(x&);
/*
x>>5即x/32,确定x在哪个数组里
x&31即x%32,确定x在对应数组里的第几小位
*/
}
void flip(int x)
{
/*将第x位反转*/
a[x>>]^=1U<<(x&);
}
int get(int x)
{
/*返回第x位的值0/1*/
return a[x>>]&(1U<<(x&));
}
}num;
//手写bitset的强大之处就是可以快速取出所有是1的位置,不过其实bitset里也封装了_Find_first()和_Find_next(x)
for(int i=;i<;++i)
{
while(true)
{
if(!num.a[i]) break;
int p=__builtin_ctz(num.a[i]);//__builtin_ctz(unsigned int x) 是通过O(1)的时间返回数字x最右边连续0的个数
printf("%d\n",i<<|p);
num.flip(i<<|p);
}
}
//手写bitset还可以取出连续的一段区间,但是封装的却不行
void make(int l,int r)
{
int shift=l&;
int y=(r-l)>>;
int j=l>>;
for(int i=;i<y;++i)
{
u num=(a.num[j]>>shift);
if(shift!=) num|=a.num[j+]<<(-shift);//注意x<<32并不是0,而是x本身
ans.num[i]^=num;
++j;
}
for(int i=l+*y;i<=r;++i)
if(a.get(i))
ans.flip(i-l);
}

决策单调性优化

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,inf=1e7;
int a[maxn+],f[maxn+][+];
int kk[maxn+][+];
int m,s,n;
struct wjmzbmr
{
int l,r,p;
}q[maxn+];
int cal(int j,int i,int p)
{
return f[p][j]+a[i]-a[p+]+;
}
int find(int j,int l,int r,int p,int pp)
{
int mid;
bool flag=;
while(l<r)
{
mid=(l+r)>>;
if(cal(j-,mid,p)>cal(j-,mid,pp)) l=mid+;else r=mid;
}
if(cal(j-,r,p)<cal(j-,r,pp)) return r;else return r+;
}
int main()
{
scanf("%d%d%d",&m,&s,&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
sort(a+,a+n+);
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
f[i][j]=inf;
memset(f[],,sizeof(f[]));
for(int i=;i<=n;++i) f[i][]=a[i]-a[]+;
for(int j=;j<=m;++j)
{
int head=,tail=;
q[]={,n,};
for(int i=;i<=n;++i)
{
while(head<tail&&q[head].r<i) ++head;
f[i][j]=cal(j-,i,q[head].p);
while(head<tail&&cal(j-,q[tail].l,i)<cal(j-,q[tail].l,q[tail].p)) --tail;
int position=find(j,q[tail].l,q[tail].r,i,q[tail].p);
if(position<=n)
{
q[tail+]={position,n,i};
q[tail].r=position-;
if(q[tail].l>q[tail].r) ++head;
++tail;
}
}
}
printf("%d\n",f[n][m]);
return ;
}

Berlekamp-Massey算法

 #include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=;
ll powmod(ll a,ll b) {ll res=;a%=mod; assert(b>=); for(;b;b>>=){if(b&)res=res*a%mod;a=a*a%mod;}return res;}
// head ll n;
namespace linear_seq {
const int N=;
ll res[N],base[N],_c[N],_md[N]; vector<int> Md;
void mul(ll *a,ll *b,int k) {
rep(i,,k+k) _c[i]=;
rep(i,,k) if (a[i]) rep(j,,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-;i>=k;i--) if (_c[i])
rep(j,,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
// printf("%d\n",SZ(b));
ll ans=,pnt=;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,,k) _md[k--i]=-a[i];_md[k]=;
Md.clear();
rep(i,,k) if (_md[i]!=) Md.push_back(i);
rep(i,,k) res[i]=base[i]=;
res[]=;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=;p--) {
mul(res,res,k);
if ((n>>p)&) {
for (int i=k-;i>=;i--) res[i+]=res[i];res[]=;
rep(j,,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,,k) ans=(ans+res[i]*b[i])%mod;
if (ans<) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(,),B(,);
int L=,m=,b=;
rep(n,,SZ(s)) {
ll d=;
rep(i,,L+) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==) ++m;
else if (*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-)%mod;
while (SZ(C)<SZ(B)+m) C.pb();
rep(i,,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+-L; B=T; b=d; m=;
} else {
ll c=mod-d*powmod(b,mod-)%mod;
while (SZ(C)<SZ(B)+m) C.pb();
rep(i,,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
vector<int> a;
int main() {
int T;
scanf("%d",&T);
a.clear();
a.pb(),a.pb(),a.pb(),a.pb(),a.pb(),a.pb();
while(T--)
{
scanf("%lld",&n);
printf("%d\n",linear_seq::gao(a,n-));
}
return ;
}

FastIO

 typedef long long LL;
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = ;
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, , BUF_SIZE, stdin);
if(pend == p1) {
IOerror = ;
return -;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror)
return;
for(x = ch - ''; (ch = nc()) >= '' && ch <= ''; x = x * + ch - '');
}
#undef BUF_SIZE
};
using namespace fastIO;

虚树

 void buildtree()
{
len=;
sort(a+,a+m+,cmp);//关键点
id.clear();//记录出现的关键点
id.push_back(a[]);
s[++len]=a[];
for(int i=;i<=m;i++)
{
int x=a[i],f=lca(s[len],x);
while(deep[f]<deep[s[len]])
{
if(deep[f]>=deep[s[len-]])
{
addedge(f,s[len],abs(deep[f]-deep[s[len]]));//虚树addedge(u,v,w)
len--;
if(f!=s[len]) s[++len]=f;
break;
}
addedge(s[len-],s[len],abs(deep[s[len-]]-deep[s[len]]));
len--;
}
if(s[len]!= x) s[++len]=x;
}
while(--len) addedge(s[len],s[len+],abs(deep[s[len+]]-deep[s[len]]));
}

单纯形法(uva10498)

#include<bits/stdc++.h>
using namespace std;
const int maxm = ; // 约束数目上限
const int maxn = ; // 变量数目上限
const double INF = 1e100;
const double eps = 1e-; struct Simplex
{
int n; // 变量个数
int m; // 约束个数
double a[maxm][maxn]; // 输入矩阵
int B[maxm], N[maxn]; // 算法辅助变量 void pivot(int r, int c)
{
swap(N[c], B[r]);
a[r][c] = / a[r][c];
for(int j = ; j <= n; j++)
if(j != c) a[r][j] *= a[r][c];
for(int i = ; i <= m; i++)
if(i != r)
{
for(int j = ; j <= n; j++)
if(j != c) a[i][j] -= a[i][c] * a[r][j];
a[i][c] = -a[i][c] * a[r][c];
}
}
bool feasible()
{
for(;;)
{
int r, c;
double p = INF;
for(int i = ; i < m; i++) if(a[i][n] < p) p = a[r = i][n];
if(p > -eps) return true;
p = ;
for(int i = ; i < n; i++) if(a[r][i] < p) p = a[r][c = i];
if(p > -eps) return false;
p = a[r][n] / a[r][c];
for(int i = r+; i < m; i++)
if(a[i][c] > eps)
{
double v = a[i][n] / a[i][c];
if(v < p) { r = i; p = v; }
}
pivot(r, c);
}
}
// 解有界返回1,无解返回0,*返回-1。b[i]为x[i]的值,ret为目标函数的值
int simplex(int n, int m, double x[maxn], double& ret)
{
this->n = n;
this->m = m;
for(int i = ; i < n; i++) N[i] = i;
for(int i = ; i < m; i++) B[i] = n+i;
if(!feasible()) return ;
for(;;)
{
int r, c;
double p = ;
for(int i = ; i < n; i++) if(a[m][i] > p) p = a[m][c = i];
if(p < eps)
{
for(int i = ; i < n; i++) if(N[i] < n) x[N[i]] = ;
for(int i = ; i < m; i++) if(B[i] < n) x[B[i]] = a[i][n];
ret = -a[m][n];
return ;
}
p = INF;
for(int i = ; i < m; i++) if(a[i][c] > eps)
{
double v = a[i][n] / a[i][c];
if(v < p) { r = i; p = v; }
}
if(p == INF) return -;
pivot(r, c);
}
}
}; //////////////// 题目相关
Simplex solver;
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) == )
{
for(int i = ; i < n; i++) scanf("%lf", &solver.a[m][i]); // 目标函数
solver.a[m][n] = ; // 目标函数常数项
for(int i = ; i < m; i++)
for(int j = ; j < n+; j++)
scanf("%lf", &solver.a[i][j]);
double ans, x[maxn];
assert(solver.simplex(n, m, x, ans) == );
ans *= m;
printf("Nasa can spend %d taka.\n", (int)floor(ans + - eps));
}
return ;
}

Split-Merge Treap(fhq treap/非旋转式treap)

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e5,inf=1e9,mod=1e6;
int pre[maxn+],ch[maxn+][],val[maxn+],key[maxn+];
int n,root,len;
int Rand()
{
int ans=;
for(int i=;i<=;++i) ans=ans*+rand()%;
return ans;
}
void split(int k,int x,int &u,int &v)
{
if(!k) u=v=;
else
{
pushdown(k);
if(x<=sz[ch[k][]]) v=k,split(ch[k][],x,u,ch[k][]);
else u=k,split(ch[k][],x-sz[ch[k][]]-,ch[k][],v);
/* if(val[k]<=x) u=k,split(ch[k][1],x,ch[k][1],v);
else v=k,split(ch[k][0],x,u,ch[k][0]); */
update(k);
}
}
int merge(int u,int v)
{
/*
将两个子树u,v合并,其中u子树的权值都小于v子树
*/
if(!u) return v;
if(!v) return u;
pushdown(u),pushdown(v);
if(key[u]<key[v])
{
ch[u][]=merge(ch[u][],v);
update(u);
return u;
}
else
{
ch[v][]=merge(u,ch[v][]);
update(v);
return v;
}
}
int newnode(int x)
{
/*
新建一个权值为x的结点
*/
++len;
val[len]=x;
ch[len][]=ch[len][]=;
key[len]=Rand()%;
return len;
}
void insert(int x)
{
/*
插入一个权值为x的结点
*/
int u,v;
split(root,x,u,v);
root=merge(merge(u,newnode(x)),v);
}
void del(int x)
{
/*
删除一个权值为x的结点
*/
int u,v,c,d;
split(root,x,u,v);
split(u,x-,c,d);
d=merge(ch[d][],ch[d][]);
u=merge(c,d);
root=merge(u,v);
}
int getpre(int k,int x)
{
/*
从以k为根的子树中找到x的前驱
*/
if(!k) return -inf;
if(x==val[k]) return x;
if(x<val[k]) return getpre(ch[k][],x);
return max(val[k],getpre(ch[k][],x));
}
int getsuf(int k,int x)
{
/*
从以k为根的子树中找到x的后继
*/
if(!k) return inf;
if(x==val[k]) return x;
if(x>val[k]) return getsuf(ch[k][],x);
return min(val[k],getsuf(ch[k][],x));
}
int main()
{
srand(time());
scanf("%d",&n);
root=;
len=;
insert(-inf);
insert(inf);
int ans=;
int a=,b=;
for(int i=;i<=n;++i)
{
int op,x;
scanf("%d%d",&op,&x);
if(op==)
{
if(b)
{
int ans1=getpre(root,x);
int ans2=getsuf(root,x);
if(ans2-x<x-ans1) ans=(ans+abs(ans2-x))%mod,del(ans2);else ans=(ans+abs(ans1-x))%mod,del(ans1);
--b;
}
else ++a,insert(x);
}
else
{
if(a)
{
int ans1=getpre(root,x);
int ans2=getsuf(root,x);
if(ans2-x<x-ans1) ans=(ans+abs(ans2-x))%mod,del(ans2);else ans=(ans+abs(ans1-x))%mod,del(ans1);
--a;
}
else ++b,insert(x);
}
}
printf("%d\n",ans);
return ;
}

自适应辛普森

 #include<bits/stdc++.h>
using namespace std;
const double eps=1e-;
double a,b,l,r;
double F(double x)
{
//Simpson公式用到的函数
return *sqrt(b*b-b*b*x*x/a/a);
}
double simpson(double l,double r)//三点Simpson法,这里要求F是一个全局函数
{
double mid=(l+r)*0.5;
return (F(l)+*F(mid)+F(r))*(r-l)/;
}
double asr(double l,double r)//自适应Simpson公式(递归过程)
{
double mid=(l+r)*0.5;
double x=simpson(l,mid),y=simpson(mid,r);
double z=simpson(l,r);
if(fabs(x+y-z)<=*eps) return x+y+(x+y-z)/15.0;
return asr(l,mid)+asr(mid,r);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lf%lf%lf%lf",&a,&b,&l,&r);
printf("%.3f\n",asr(l,r));
}
return ;
}

点分治

 void getroot(int k,int fa)
{
sz[k]=mx[k]=;
for(auto u:g[k])
{
if(u==fa||vis[u]) continue;
getroot(u,k);
sz[k]+=sz[u];
mx[k]=max(mx[k],sz[u]);
}
mx[k]=max(mx[k],sum-sz[k]);
if(mx[k]<mx[root]) root=k;
}
void getdeep(int k,int fa,int f)
{
father[k]=fa;
dep[k]=dep[fa]+;
maxd[k]=dep[k];
par[k]=f;
L[k]=++t;
p[t]=k;
for(auto u:g[k])
{
if(u==fa||vis[u]) continue;
getdeep(u,k,f);
maxd[k]=max(maxd[k],maxd[u]);
}
R[k]=t;
}
void solve(int k)
{
t=;
maxd[k]=dep[k]=;
L[k]=++t;
p[]=k;
for(auto u:g[k])
{
if(vis[u]) continue;
getdeep(u,k,u);
maxd[k]=max(maxd[k],maxd[u]);
}
R[k]=t; for(int i=;i<=maxd[k];++i) s[i]=;
for(int i=;i<=t;++i)
{
int u=p[i];
if(u>n) continue;
++s[dep[u]];
if(dep[u]==D) res[k][par[u]]++;
}
ss[]=s[];
for(int i=;i<=maxd[k];++i) ss[i]=ss[i-]+s[i];
ans[k]+=ss[min(D-,maxd[k])];
for(int i=;i<=t;++i)
{
int u=p[i];
if(D--dep[u]>=) ans[u]+=ss[min(D--dep[u],maxd[k])];
if(D>=dep[u]&&D-dep[u]<=maxd[k])
res[u][father[u]]+=s[D-dep[u]];
} for(auto u:g[k])
{
if(vis[u]) continue;
for(int i=;i<=maxd[u];++i) s[i]=ss[i]=;
for(int i=L[u];i<=R[u];++i)
{
int v=p[i];
if(v>n) continue;
++s[dep[v]];
}
ss[]=s[];
for(int i=;i<=maxd[u];++i) ss[i]=ss[i-]+s[i];
for(int i=L[u];i<=R[u];++i)
{
int v=p[i];
if(D--dep[v]>=) ans[v]-=ss[min(D--dep[v],maxd[u])];
if(D>=dep[v]&&D-dep[v]<=maxd[u])
res[v][father[v]]-=s[D-dep[v]];
}
}
vis[k]=;
for(auto u:g[k])
{
if(vis[u]) continue;
sum=sz[u];
root=;
getroot(u,);
solve(root);
}
}

带修改莫队

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e6;
int block,n,m,num,s,l,r;
struct Q
{
int l,r,t,id;
bool operator < (const Q& x) const
{
if(l/block!=x.l/block) return l<x.l;
if(r/block!=x.r/block) return r<x.r;
return t<x.t;
}
}q[maxn+];
struct wjmzbmr
{
int pos,from,to,t;
}c[maxn+];
int a[maxn+],b[maxn+],color[maxn+],ans[maxn+];
void add(int x,int type)
{
if(color[x]) --s;
color[x]+=type;
if(color[x]) ++s;
}
void ins(wjmzbmr q)
{
if(q.pos>=l&&q.pos<=r) add(q.from,-),add(q.to,);
a[q.pos]=q.to;
}
void del(wjmzbmr q)
{
if(q.pos>=l&&q.pos<=r) add(q.to,-),add(q.from,);
a[q.pos]=q.from;
}
int main()
{
int T;
scanf("%d%d",&n,&T);
for(int i=;i<=n;++i) scanf("%d",&b[i]),a[i]=b[i];
int time=;
while(T--)
{
char s[];
int x,y;
scanf("%s%d%d",s,&x,&y);
if(s[]=='Q') ++m,q[m]={x,y,++time,m};
else c[++num]={x,,y,++time};
}
for(int i=;i<=num;++i) c[i].from=b[c[i].pos],b[c[i].pos]=c[i].to;
c[num+].t=;
block=(int)(ceil(pow(n,2.0/)));
sort(q+,q+m+);
l=,r=;
int now=;
s=;
for(int i=;i<=m;++i)
{
while(r<q[i].r) add(a[++r],);
while(l>q[i].l) add(a[--l],);
while(r>q[i].r) add(a[r--],-);
while(l<q[i].l) add(a[l++],-);
while(c[now+].t<q[i].t) ins(c[++now]);
while(c[now].t>q[i].t) del(c[now--]);
ans[q[i].id]=s;
}
for(int i=;i<=m;++i) printf("%d\n",ans[i]);
return ;
}

可持久化堆优化k短路

 /*
可持久化堆优化k短路
求最短路径树:O(nlogn)
求k短路:O(mlogm+klogk)
空间复杂度:O(mlogm),但具体开数组要注意常数,要看执行merge操作的次数
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=,maxm=,maxsize=;//maxsize是堆的最大个数
const long long inf=1000000000000000LL;
int a[maxn+];
long long s[maxn+];
int n,k,m,len,tot;
int S,T;
vector<int> g1[maxn+];
int mi[maxn+],mx[maxn+];
int head[maxn+],nx[maxm+];
long long dis[maxn+];
int pos[maxn+],rt[maxn+];
struct Edge
{
int to;
long long w;
}e[maxm+];
struct node
{
/*
u是当前堆顶的节点编号
key是当前堆顶对应边的权值,边的权值定义为:走这条边要多绕多少路
l,r分别是堆左右儿子的地址
*/
int u;
long long key;
int l,r;
}H[maxsize+];
struct heapnode
{
/*
求k短路时候用到的数据结构
len表示1~倒数第二条边的边权和
root表示倒数第二条边的tail的H[tail],其中堆顶就是最后一条边
*/
long long len;
int root;
bool operator < (const heapnode& x) const
{
return len+H[root].key>x.len+H[x.root].key;
}
};
priority_queue<heapnode> q;
void addedge(int u,int v,long long w)
{ //printf("%d %d %lld\n",u,v,w);
e[++len]={v,w};
nx[len]=head[u];
head[u]=len;
}
void dfs(int k,int fa)
{
s[k]=a[k];
bool flag=;
mi[k]=n+;
mx[k]=;
for(int i=;i<g1[k].size();++i)
if(g1[k][i]!=fa)
{
flag=;
dfs(g1[k][i],k);
s[k]+=s[g1[k][i]];
mi[k]=min(mi[k],mi[g1[k][i]]);
mx[k]=max(mx[k],mx[g1[k][i]]);
}
if(!flag) mi[k]=mx[k]=++m;
}
int newnode(int u,long long key)
{
++tot;
H[tot]={u,key,,};
return tot;
}
int merge(int u,int v)
{
/*
merge两个堆u和v
这里是采用随机堆,方便合并,方便持久化
*/
if(!u) return v;
if(!v) return u;
if(H[v].key<H[u].key) swap(u,v);
int k=++tot;
H[k]=H[u];
if(rand()%) H[k].l=merge(H[k].l,v);
else H[k].r=merge(H[k].r,v);
return k;
}
void Kshort()
{
/*
求k短路
*/
dis[T]=;
for(int i=;i<T;++i) dis[i]=inf;
tot=;
for(int i=m-;i>=;--i)
{
/*
DAG图求最短路径树
*/
int fa=;
for(int j=head[i];j!=-;j=nx[j])
if(dis[i]>e[j].w+dis[e[j].to])
{
dis[i]=e[j].w+dis[e[j].to];
pos[i]=j;
fa=e[j].to;
}
rt[i]=rt[fa];
for(int j=head[i];j!=-;j=nx[j])
if(j!=pos[i])
{
//printf("ce : %d %d\n",i,e[j].to);
rt[i]=merge(rt[i],newnode(e[j].to,e[j].w+dis[e[j].to]-dis[i]));
}
}
//printf("tot : %d\n",tot);
//printf("len : %d\n",len);
//printf("m : %d\n",m);
//for(int i=0;i<=T;++i) printf("%d : %lld %d\n",i,dis[i],pos[i]);
printf("%lld\n",dis[S]+s[]);
heapnode now={0LL,rt[S]};
if(now.root) q.push(now);
while(--k&&!q.empty())
{
/*
每次从优先队列队首取出最小的边集
每个边集对对应一种合法的k短路走法
有两种扩展方法
第一种:将最后一条边换成所在堆的次小元素(相当于从堆里把堆顶删除)
第二种:新加一条边,即从最后一条边继续往后走
*/
now=q.top();
q.pop();
printf("%lld\n",now.len+H[now.root].key+dis[S]+s[]);
int id=merge(H[now.root].l,H[now.root].r);
//printf("%d : %d %lld\n",id,H[id].u,H[id].key);
if(id)
q.push({now.len,id});
now.len+=H[now.root].key;
if(rt[H[now.root].u])
q.push({now.len,rt[H[now.root].u]});
}
}
int main()
{
srand(time());
scanf("%d%d",&n,&k);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
for(int i=;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
g1[u].push_back(v);
g1[v].push_back(u);
}
dfs(,);
for(int i=;i<=n+;++i) head[i]=-;
for(int i=;i<=n;++i) addedge(mi[i]-,mx[i],-s[i]);
for(int i=;i<m;++i) addedge(i,i+,);
S=,T=m;
Kshort();
return ;
}

pbds里的rbtree

 #include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
//#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> rbtree;
/*
tree中不能有重复元素
若要能支持重复元素,可以将int改成pair<int,int>
*/
int main()
{
rbtree s;
s.insert();
s.insert();
s.insert();
printf("%d\n",s.order_of_key());//s.order_of_key(x) s里面有多少数<x
printf("%d\n",*s.find_by_order());//s.find_by_order(k) s里面第k+1小的数是谁
return ;
}

lagrange插值

 void mul(int *a,int d,int c)
{
/*
a*(x-c)
*/
int b[maxn+];
// memset(b,0,sizeof(b));
for(int i=;i<=d;++i) b[i]=a[i];
for(int i=d+;i>=;--i) a[i]=a[i-];
a[]=;
for(int i=;i<=d;++i)
{
a[i]=(a[i]-1LL*b[i]*c)%mod;
if(a[i]<) a[i]+=mod;
}
}
void div(int *a,int d,int c,int *ans)
{
/*
ans=a/(x-c)
*/
ans[d-]=a[d];
for(int i=d-;i>=;--i)
ans[i]=(a[i+]+1LL*c*ans[i+])%mod;
}
void lagrange(int *y,int d,int *p)
{
/*
(0,y[0]),(1,y[1]),...,(d,y[d])
插出的系数放p中
*/
int tmp[maxn+],now[maxn+];
memset(tmp,,sizeof(tmp));
memset(now,,sizeof(now));
tmp[]=;
for(int i=;i<=d;++i)
{
mul(tmp,i,i);
}
for(int i=;i<=d;++i)
{
for(int j=;j<=d;++j) now[j]=;
div(tmp,d+,i,now);
long long q=;
for(int j=;j<=d;++j)
if(i!=j)
{
q=q*(i-j)%mod;
if(q<) q+=mod;
}
q=inv(q);
q=q*y[i]%mod;
for(int j=;j<=d;++j) now[j]=1LL*now[j]*q%mod;
for(int j=;j<=d;++j) p[j]=(p[j]+now[j])%mod;
}
}

lagrange插值(插系数)

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,mod=1e9+;
char s[+];
int a[maxn+][maxn+],b[maxn+][maxn+],res[maxn+][maxn+];
int y[maxn+];
int ans[maxn+],p[maxn+],num[maxn+];
int n,k,d;
int det(int a[maxn+][maxn+],int n)
{
long long ans=;
for(int i=;i<=n;++i)
for(int j=i+;j<=n;++j)
while(a[j][i])
{
int u=a[i][i]/a[j][i];
for(int k=;k<=n;++k)
{
a[i][k]=(a[i][k]-1LL*u*a[j][k])%mod;
if(a[i][k]<) a[i][k]+=mod;
swap(a[i][k],a[j][k]);
}
ans=-ans;
}
for(int i=;i<=n;++i) ans=ans*a[i][i]%mod;
return ans;
}
void mul(int *a,int d,int c)
{
/*
a*(x-c)
*/
int b[maxn+];
for(int i=;i<=d;++i) b[i]=a[i];
for(int i=d+;i>=;--i) a[i]=a[i-];
a[]=;
for(int i=;i<=d;++i)
{
a[i]=(a[i]-1LL*b[i]*c)%mod;
if(a[i]<) a[i]+=mod;
}
}
void div(int *a,int d,int c,int *ans)
{
/*
ans=a/(x-c)
*/
ans[d-]=a[d];
for(int i=d-;i>=;--i)
ans[i]=(a[i+]+1LL*c*ans[i+])%mod;
}
long long Pow(long long a,long long b)
{
long long ans=;
while(b)
{
if(b&) ans=ans*a%mod;
a=a*a%mod;
b>>=;
}
return ans;
}
long long inv(long long a)
{
return Pow(a,mod-2LL);
}
void lagrange(int *y,int d,int *p)
{
int tmp[maxn+],now[maxn+];
memset(tmp,,sizeof(tmp));
memset(now,,sizeof(now));
tmp[]=;
for(int i=;i<=d;++i)
{
mul(tmp,i,i);
}
for(int i=;i<=d;++i)
{
for(int j=;j<=d;++j) now[j]=;
div(tmp,d+,i,now);
long long q=;
for(int j=;j<=d;++j)
if(i!=j)
{
q=q*(i-j)%mod;
if(q<) q+=mod;
}
q=inv(q);
q=q*y[i]%mod;
for(int j=;j<=d;++j) now[j]=1LL*now[j]*q%mod;
for(int j=;j<=d;++j) p[j]=(p[j]+now[j])%mod;
}
}
void mul(int *a,int *b)
{
int tmp[maxn+];
memset(tmp,,sizeof(tmp));
for(int i=;i<k;++i)
for(int j=;j<k;++j)
tmp[i+j]=(tmp[i+j]+1LL*a[i]*b[j])%mod;
for(int i=k*-;i>=k;--i)
{
for(int j=k-;j>=;--j)
{
tmp[i-k+j]=(tmp[i-k+j]-1LL*tmp[i]*p[j])%mod;
if(tmp[i-k+j]<) tmp[i-k+j]+=mod;
}
tmp[i]=;
}
for(int i=;i<k;++i) a[i]=tmp[i];
}
void mul(int a[maxn+][maxn+],int b[maxn+][maxn+],int n)
{
int ans[maxn+][maxn+];
memset(ans,,sizeof(ans));
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
for(int k=;k<=n;++k)
ans[i][j]=(ans[i][j]+1LL*a[i][k]*b[k][j])%mod;
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
a[i][j]=ans[i][j];
}
int main()
{
scanf("%s%d",s,&k);
n=strlen(s);
for(int i=;i<=k;++i)
for(int j=;j<=k;++j)
scanf("%d",&b[i][j]),b[i][j]=-b[i][j];
for(int x=;x<=k;++x)
{
for(int i=;i<=k;++i)
for(int j=;j<=k;++j)
a[i][j]=b[i][j];
for(int i=;i<=k;++i) a[i][i]=(b[i][i]+x)%mod;
y[x]=det(a,k);
}
lagrange(y,k,p);
ans[]=,num[]=;
for(int i=n-;i>=;--i)
{
if(s[i]=='') mul(ans,num);
mul(num,num);
}
for(int i=;i<=k;++i)
for(int j=;j<=k;++j)
b[i][j]=-b[i][j];
memset(a,,sizeof(a));
for(int i=;i<=k;++i) a[i][i]=;
for(int d=;d<=k;++d)
{
for(int i=;i<=k;++i)
for(int j=;j<=k;++j)
res[i][j]=(res[i][j]+1LL*ans[d]*a[i][j])%mod;
mul(a,b,k);
}
for(int i=;i<=k;++i)
{
for(int j=;j<=k;++j)
{
if(res[i][j]<) res[i][j]+=mod;
printf("%d",res[i][j]);
if(j!=k) printf(" ");
}
printf("\n");
}
return ;
}

计算几何模板

 typedef double db;
const db eps=1e-;
struct Point
{
/*点类*/
db x,y;
Point(){}
Point(db _x,db _y):x(_x),y(_y){}
Point operator + (const Point &t)const
{
return Point(x+t.x,y+t.y);
}
Point operator - (const Point &t)const
{
return Point(x-t.x,y-t.y);
}
Point operator * (const db &t)const
{
return Point(x*t,y*t);
}
Point operator / (const db &t)const
{
return Point(x/t,y/t);
}
db operator * (const Point &t)const
{
return x*t.y-y*t.x;
}
db len()const
{
return sqrtl(x*x+y*y);
}
Point rot90()const
{
return Point(-y,x);
}
};
struct Complex
{
/*复数类,用于旋转*/
db x,y;
Complex(db x=0.0,db y=0.0):x(x),y(y){}
Complex operator + (const Complex &t)const
{
return Complex(x+t.x,y+t.y);
}
Complex operator - (const Complex &t)const
{
return Complex(x-t.x,y-t.y);
}
Complex operator * (const Complex &t)const
{
return Complex(x*t.x-y*t.y,x*t.y+y*t.x);
}
Complex operator / (const Complex &t)const
{
return Complex((x*t.x+y*t.y)/(t.x*t.x+t.y*t.y),(y*t.x-x*t.y)/(t.x*t.x+t.y*t.y));
}
};
struct Circle
{
/*圆类*/
Point o;
db r;
Circle(){}
Circle(Point _o,db _r):o(_o),r(_r){}
friend vector<Point> operator & (const Circle &c1,const Circle &c2)
{
/*
若两圆相离,返回空
若两圆相切,返回两个相同的点
若两圆相交,返回两个不同的点
*/
db d=(c1.o-c2.o).len();
if(d>c1.r+c2.r+eps||d<fabs(c1.r-c2.r)-eps) return vector<Point>();
db dt=(c1.r*c1.r-c2.r*c2.r)/d,d1=(d+dt)/;
Point dir=(c2.o-c1.o)/d,pcrs=c1.o+dir*d1;
dt=sqrt(max(.0L,c1.r*c1.r-d1*d1)),dir=dir.rot90();
return vector<Point>{pcrs+dir*dt,pcrs-dir*dt};
}
};
void calcentre()
{
/*
计算凸多边形的重心
将凸多边形划分成若干小三角形,求出三角形的重心,然后根据小三角形面积求加权平均
*/
db area=0.0;
for(int i=;i<n;++i) area+=(a[i+]-a[i])*(a[]-a[i]);
g=Point(,);
for(int i=;i<n;++i)
{
db s=(a[i+]-a[i])*(a[]-a[i]);
g=g+(a[]+a[i]+a[i+])/3.0*(s/area);
}
}

k^2logn求线性递推

 #include<bits/stdc++.h>
using namespace std;
const int maxn=,mod=;
int a[maxn+],p[maxn+],ans[maxn+],num[maxn+];
int h[maxn+],tmp[maxn+];
int n,k;
void mul(int *a,int *b,int *ans)
{
for(int i=;i<=*k;++i) tmp[i]=;
for(int i=;i<k;++i)
for(int j=;j<k;++j)
tmp[i+j]=(tmp[i+j]+1LL*a[i]*b[j])%mod;
for(int i=*k-;i>=k;--i)
{
for(int j=k-;j>=;--j)
tmp[i-k+j]=(tmp[i-k+j]-1LL*tmp[i]*p[j])%mod,tmp[i-k+j]=(tmp[i-k+j]+mod)%mod;
tmp[i]=;
}
for(int i=;i<k;++i) ans[i]=tmp[i];
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=k;++i) scanf("%d",&a[i]);
for(int i=;i<k;++i) scanf("%d",&h[i]);
p[k]=;
for(int i=;i<=k;++i) p[k-i]=mod-a[i];
for(int i=k;i<*k;++i)
for(int j=;j<=k;++j)
{
h[i]=h[i]+1LL*h[i-j]*a[j]%mod;
h[i]%=mod;
}
if(n<*k) return *printf("%d\n",h[n]);
int b=n-k+;
num[]=,ans[]=;
while(b)
{
if(b&) mul(ans,num,ans);
mul(num,num,num);
b>>=;
}
long long res=;
for(int i=;i<k;++i) res=(res+1LL*ans[i]*h[i+k-])%mod;
printf("%lld\n",(res+mod)%mod);
return ;
}

数位dp

 #include<bits/stdc++.h>
using namespace std;
const int mod=1e9+;
int dp[][][];
int a[];
long long n;
int dfs(int len,int pre,int sum,bool flag)
{
if(!flag&&dp[len][pre][sum]!=-) return dp[len][pre][sum];
if(!len) return abs(sum-);
int ans=;
int limit=flag?a[len]:;
for(int i=;i<=limit;++i)
{
if(pre==)
{
if(i) ans=(ans+dfs(len-,i,sum,flag&&i==a[len]))%mod;
else ans=(ans+dfs(len-,pre,sum,flag&&i==a[len]))%mod;
}
else
{
if(pre==i) ans=(ans+dfs(len-,i,sum+,flag&&i==a[len]))%mod;
else ans=(ans+dfs(len-,i,sum-,flag&&i==a[len]))%mod;
}
}
if(!flag) dp[len][pre][sum]=ans;
return ans;
}
int main()
{
memset(dp,-,sizeof(dp));
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
int len=;
while(n)
{
a[++len]=n%;
n/=;
}
printf("%d\n",dfs(len,,+,));
}
return ;
}

BigInt

 typedef long long LL;
struct BigInt
{
static const int BASE = ; //基数
static const int WIDTH = ; //基宽
vector<int> s; //存储 //构造函数 -- 使用LL
BigInt(long long num = )
{
*this = num;
} //赋值运算符 -- 使用LL
BigInt operator = (long long num)
{
s.clear();
do
{
s.push_back(num % BASE);
num /= BASE;
}
while(num > );
return *this;
}
//赋值运算符 -- 使用string
BigInt operator = (const string& str)
{
s.clear();
int x, len = (str.length() - ) / WIDTH + ;
for(int i = ; i < len; i++)
{
int end = str.length() - i*WIDTH;
int start = max(, end - WIDTH);
sscanf(str.substr(start, end-start).c_str(), "%d", &x);
s.push_back(x);
}
return *this;
} //比较运算符
bool operator < (const BigInt& b) const
{
if(s.size() != b.s.size()) return s.size() < b.s.size();
for(int i = s.size()-; i >= ; i--)
if(s[i] != b.s[i]) return s[i] < b.s[i];
return false; //相等
}
bool operator > (const BigInt& b) const
{
return b < *this;
}
bool operator <= (const BigInt& b) const
{
return !(b < *this);
}
bool operator >= (const BigInt& b) const
{
return !(*this < b);
}
bool operator != (const BigInt& b) const
{
return b < *this || *this < b;
}
bool operator == (const BigInt& b) const
{
return !(b < *this) && !(*this < b);
} //重载输入输出
friend ostream& operator << (ostream &out, const BigInt& x)
{
out << x.s.back();
for(int i = x.s.size()-; i >= ; i--)
{
char buf[];
sprintf(buf, "%08d", x.s[i]);
for(int j = ; j < strlen(buf); j++) out << buf[j];
}
return out;
}
friend istream& operator >> (istream &in, BigInt& x)
{
string s;
if(!(in >> s)) return in;
x = s;
return in;
} //加法
BigInt operator + (const BigInt& b) const
{
BigInt c;
c.s.clear();
for(int i = , g = ; ; i++)
{
if(g == && i >= s.size() && i >= b.s.size()) break;
int x = g;
if(i < s.size()) x += s[i];
if(i < b.s.size()) x += b.s[i];
c.s.push_back(x % BASE);
g = x / BASE;
}
return c;
} //加等于
BigInt operator += (const BigInt& b)
{
*this = *this + b;
return *this;
} //减法 -- 大减小 -- 其他的在外部处理
BigInt operator - (const BigInt& b) const
{
BigInt c;
c.s.clear();
if((*this) == b) return c = ;
for(int i = , g = ; ; ++i)
{
if(g == && i >= s.size() && i >= b.s.size()) break;
int x = -g;
g = ;
if(i < s.size()) x += s[i];
if(i < b.s.size()) x -= b.s[i];
if(x < ) x += BASE, ++g;
c.s.push_back(x);
}
for(int i = c.s.size()-; i >= && c.s[i] == ; --i) c.s.pop_back();
return c;
} //乘法 -- 未使用FFT
BigInt operator * (const BigInt& b) const
{
int s1 = s.size(), s2 = b.s.size();
vector<LL> v(s1+s2+,);
BigInt c;
c.s.resize(s1+s2, );
for(int i = ; i < s1; ++i) //相乘
for(int j = ; j < s2; ++j)
{
v[i+j] += (LL)s[i]*b.s[j];
}
for(int i = ; i < s1+s2; ++i) //进位
{
v[i+] += v[i]/BASE;
v[i] %= BASE;
c.s[i] = v[i];
}
for(int i = c.s.size()-; i >= && c.s[i] == ; --i) c.s.pop_back();
return c;
} //除法 -- 二分
BigInt operator / (const BigInt& b) const
{
int s1 = s.size(), s2 = b.s.size();
int len = s1-s2;
BigInt c, x = *this, y = b;
if(len < ) return c = ; c.s.resize(len+, );
for(int i = len; i >= ; --i)
{
//先将除数对齐
y.s.resize(s2+i,);
for(int j = s2+i-; j >= ; --j)
{
if(j >= i) y.s[j] = b.s[j-i];
else y.s[j] = ;
}
//再二分找商
int L = , R = BASE;
BigInt t;
while(L < R)
{
int mid = (L+R)>>;
t = mid;
if(t*y > x) R = mid;
else L = mid+;
}
c.s[i] = L-;
//更新被除数
t = L-;
x = x - t*y;
}
for(int i = c.s.size()-; i >= && c.s[i] == ; --i) c.s.pop_back();
return c;
} //取模
BigInt operator % (const BigInt& b) const
{
return (*this) - (*this)/b * b;
} //开方 -- 二分 -- 浮点数可放大1e4精确一位
BigInt Sqrt()
{
BigInt L = , R = *this;
while(L < R)
{
BigInt mid = (L+R)/;
if(mid*mid > *this) R = mid;
else L = mid+;
}
return L-;
}
};

CRT

 void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b)
{
d=a,x=,y=;
return;
}
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
ll inv(ll a,ll n)
{
ll d,x,y;
gcd(a,n,d,x,y);
return d==?(x+n)%n:-;
}
ll CRT(int n,ll *a,ll *m)
{
/*n个方程 x=a[i] (mod m[i]) (0<=i<n)*/
ll M=,d,y,x=;
for(int i=;i<n;++i) M*=m[i];
for(int i=;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;
}

类欧几里得

 typedef long long ll;
const ll mod = ; ll solve(ll a,ll b,ll c,ll n)
{
/*
计算 \sum_{i=0..n} (ax+b)/c 的值
即第一象限直线y=(ax+b)/c下方纵坐标为正数的整点的个数
*/
if(a==)
return (b/c)*(n+)%mod;
if(a>=c)
return (n*(n+)/%mod*(a/c)%mod+solve(a%c,b,c,n))%mod;
if(b>=c)
return ((b/c)*(n+)%mod+solve(a,b%c,c,n))%mod;
//LL m=(a*n+b)/c%MOD;
ll m=(n/c*a+(n%c*a+b)/c);
return ((m%mod)*(n%mod)%mod-solve(c,c-b-,a,m-)+mod)%mod;
}
ll cal(ll a,ll b,ll c,ll n)
{
/*
计算y=(ax+b)/c下方整点个数,x=0..n
要求a>=0,c>0
*/
if(b>=) return (solve(a,b,c,n)+n%mod+)%mod;
ll x=(-b)/a;
if(x*a+b<) ++x;
if(n<x) return ;
b+=a*x;
return (solve(a,b,c,n-x)+(n-x)%mod+)%mod;
}

笛卡尔树

 pair<int,int> a[maxn+];
int lson[maxn+],rson[maxn+],fa[maxn+],root;
int s[maxn+];
void buildtreap(pair<int,int> *a)
{
/*
大根堆
*/
int top=;
for(int i=;i<=n;++i) rson[i]=lson[i]=fa[i]=;
for(int i=;i<=n;++i)
{
int last=;
while(top>=&&a[i]>a[s[top]]) last=s[top--];
if(top) rson[s[top]]=i,fa[i]=s[top];
lson[i]=last;
if(!last) fa[last]=i;
s[++top]=i;
}
root=s[];
}

杜教筛求莫比乌斯函数前缀和

 #include <bits/stdc++.h>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
typedef long long ll;
const int maxn = 1e6 + ;
int prime[maxn], tot, mu[maxn], Mu[maxn];
bool check[maxn];
map<ll, ll> M;
map<ll, ll> T;
void calmu()
{
mu[] = ;
for (int i = ; i < maxn; i++)
{
if (!check[i])
prime[tot++] = i, mu[i] = -;
for (int j = ; j < tot; j++)
{
if (i * prime[j] >= maxn) break;
check[i * prime[j]] = true;
if (i % prime[j] == )
{
mu[i * prime[j]] = ;
break;
}
else
mu[i * prime[j]] = -mu[i];
}
}
for (int i = ; i < maxn; i++)
Mu[i] = Mu[i - ] + mu[i];
}
ll work(ll x)
{
/*
求 mu[1]+mu[2]+...+mu[x]
*/
if (x < maxn) return Mu[x];
if (M[x]) return M[x];
ll ans = ;
for (ll i = , last; i <= x; i = last + )
{
last = x / (x / i);
ans -= (last - i + ) * work(x / i);
}
return M[x] = ans;
}

O(1)快速乘

 inline ll multi(ll x,ll y,ll mod)
{
ll tmp=(x*y-(ll)((long double)x/mod*y+1.0e-8)*mod);
return tmp< ? tmp+mod : tmp;
}

莫队算法

 #include<bits/stdc++.h>
using namespace std;
const int maxn=;
int pos[maxn+],a[maxn+];
struct wjmzbmr
{
int l,r,k1,k2,id,ans;
}q[maxn+];
int block,n,m;
int color[maxn+],cnt[+],ans[maxn+];
int num[maxn+],sum[maxn+][+];
bool cmp(const wjmzbmr a,const wjmzbmr b)
{
if(a.l/block!=b.l/block) return a.l<b.l;
if((a.l/block)&) return a.r>b.r;else return a.r<b.r;
}
void update(int x,int type)
{
--color[num[x]];
if(color[num[x]]==) --cnt[num[x]/block];
--sum[num[x]][x/block];
num[x]+=type;
++sum[num[x]][x/block];
if(color[num[x]]==) ++cnt[num[x]/block];
++color[num[x]];
}
int query(int k1,int k2)
{
int i=;
for(i=;i<=n/block;++i)
if(cnt[i]<k1) k1-=cnt[i];
else break;
int turn;
for(turn=block*i;turn<block*(i+);++turn)
{
if(color[turn]>) --k1;
if(k1==) break;
}
for(i=;i<=;++i)
if(sum[turn][i]<k2) k2-=sum[turn][i];
else break;
int ans;
for(ans=block*i;ans<block*(i+);++ans)
{
if(num[ans]!=turn) continue;
if(num[ans]>) --k2;
if(k2==) break;
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=;i<=m;++i) scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].k1,&q[i].k2),q[i].id=i;
block=sqrt(n);
sort(q+,q+m+,cmp);
block=;
int l=,r=;
for(int i=;i<=m;++i)
{
while(l>q[i].l) update(a[--l],);
while(r<q[i].r) update(a[++r],);
while(r>q[i].r) update(a[r--],-);
while(l<q[i].l) update(a[l++],-);
ans[q[i].id]=query(q[i].k1,q[i].k2);
}
for(int i=;i<=m;++i) printf("%d\n",ans[i]);
return ;
}