IO
快读
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
namespace in{
char buf[1<<21],*p1=buf,*p2=buf;
inline int getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
template <typename T>inline void read(T& t){
t=0;int f=0;char ch=getc();while (!isdigit(ch)){if(ch=='-')f = 1;ch=getc();}
while(isdigit(ch)){t=t*10+ch-48;ch = getc();}if(f)t=-t;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
}
namespace out{
char buffer[1<<21];int p1=-1;const int p2 = (1<<21)-1;
inline void flush(){fwrite(buffer,1,p1+1,stdout),p1=-1;}
inline void putc(const char &x) {if(p1==p2)flush();buffer[++p1]=x;}
template <typename T>void write(T x) {
static char buf[15];static int len=-1;if(x>=0){do{buf[++len]=x%10+48,x/=10;}while (x);}else{putc('-');do {buf[++len]=-(x%10)+48,x/=10;}while(x);}
while (len>=0)putc(buf[len]),--len;
}
}
using namespace std;
signed main(){
out::flush();
return 0;
}
图论
SPFA
const int maxn=10010;
const int maxm=500010;
struct spfa{
int s,t,c;bool vis[maxn];
int head[maxn],path[maxn];
struct node{
int nxt,to,w;
}a[maxm<<1];
inline int relax(int u,int v,int w){
if(path[v]>path[u]+w){
path[v]=path[u]+w;
return 1;
}return 0;
}
inline void add(int u,int v,int w){a[c].to=v;a[c].w=w;a[c].nxt=head[u];head[u]=c++;}
inline void init(int _s,int _t){s=_s,t=_t;memset(head,0,sizeof head);c=1;}
void deal(){
int u,v,num=0;long long x=0;list<int> q;
memset(path,0x3f,sizeof path);
memset(vis,false,sizeof vis);
path[s]=0;vis[s]=true;q.push_back(s);num++;
while(!q.empty()){
u=q.front();q.pop_front();
num--;x-=path[u];
while(num&&path[u]>x/num){q.push_back(u);u=q.front();q.pop_front();}
vis[u]=false;
for(int i=head[u];i;i=a[i].nxt){
v=a[i].to;
if(relax(u,v,a[i].w)&&!vis[v]){
if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
else q.push_back(v);num++;x+=path[v];vis[v]=true;
}
}
}
}
};
Dinic
const int maxn=4010,maxe=100010*2;
struct Graph{
struct node{
int v,w,nxt;
}e[maxe<<1];
int head[maxn],cur[maxn],tot;
int dis[maxn];
int s,t;
void init(int _s,int _t){s=_s,t=_t;tot=1;memset(head,0,sizeof head);}
Graph(int _s=0,int _t=0){init(_s,_t);}
void add(int u,int v,int w){
//printf("%d %d %d\n",u,v,w);
e[++tot]=(node){v,w,head[u]},head[u]=tot;
e[++tot]=(node){u,0,head[v]},head[v]=tot;
}
#define v e[i].v
inline bool bfs(){
queue<int>q;
memset(dis,0,sizeof dis);
memcpy(cur,head,sizeof head);
dis[s]=1;q.push(s);
while(q.size()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt)
if(!dis[v]&&e[i].w){
dis[v]=dis[u]+1,q.push(v);
if(v==t)return true;
}
}
return false;
}
int dfs(int u,int flow){
if(u==t)return flow;
int rest=flow;
for(int i=cur[u];i&&rest;i=e[i].nxt){
if(dis[v]==dis[u]+1&&e[i].w){
int tmp=dfs(v,min(rest,e[i].w));
rest-=tmp,e[i].w-=tmp,e[i^1].w+=tmp;
}
cur[u]=i;
}
if(rest==0)dis[u]=-1;
return flow-rest;
}
#undef v
int dinic(){
int ans=0;
while(bfs())
while(int sth=dfs(s,2e9))
ans+=sth;
return ans;
}
}G;
MincostMaxflow
const int maxn=100005;
const int maxe=100005;
struct Graph{
int s,t;
int dis[maxn],pre[maxn],lste[maxn],flow[maxn];
bool inq[maxn];
struct node{
int v,w,cost,nxt;
node(int _v=0,int _w=0,int _c=0,int _n=0){v=_v,w=_w,cost=_c,nxt=_n;}
}e[maxe];
int tot,head[maxn];
void init(int _s,int _t){
memset(head,0,sizeof head);
tot=1;s=_s,t=_t;
}
inline void add(int u,int v,int w,int c){
e[++tot]=node(v,w,c,head[u]);head[u]=tot;
e[++tot]=node(u,0,-c,head[v]);head[v]=tot;
}
bool spfa(){
queue<int>q;
memset(dis,63,sizeof dis);
memset(flow,63,sizeof flow);
memset(inq,0,sizeof inq);
dis[s]=0,pre[t]=-1;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();inq[u]=0;
#define v e[i].v
for(int i=head[u];i;i=e[i].nxt){
if(e[i].w>0&&dis[v]>dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost;
pre[v]=u,lste[v]=i;//lste 表示顶点v是由哪条边过来的
flow[v]=min(flow[u],e[i].w);
if(!inq[v])inq[v]=1,q.push(v);
}
}
#undef v
}
return pre[t]!=-1;
}
pair<int,int> mcmf(){
int mincost=0,maxflow=0;
while(spfa()){
int u=t;
maxflow+=flow[t],mincost+=flow[t]*dis[t];
while(u!=s){
int E=lste[u];
e[E].w-=flow[t],e[E^1].w+=flow[t];
u=pre[u];
}
}
return make_pair(mincost,maxflow);
}
}G;
数学
自适应辛普森法
struct Simpson{
double (*f)(double);
double Eps;
Simpson(double (*_f)(double),double _E){f=_f;Eps=_E;}
inline double simpson(double l,double r){
double mid=(l+r)/2;
return (f(l)+4*f(mid)+f(r))*(r-l)/6;
}
double asr(double l,double r,double eps,double ans){
double mid=(l+r)/2;
double l_=simpson(l,mid),r_=simpson(mid,r);
if(fabs(l_+r_-ans)<=15*eps)return l_+r_+(l_+r_-ans)/15;
return asr(l,mid,eps/2,l_)+asr(mid,r,eps/2,r_);
}
double asr(double l,double r){
return asr(l,r,Eps,simpson(l,r));
}
};
凸包
namespace Convex_Hull{
#define sq(x) (x)*(x)
struct node{
double x,y;
}p[1000000+1000],s[1000000+1000];
int n=0,cnt;
double check(node a1,node a2,node b1,node b2){
return (a2.x-a1.x)*(b2.y-b1.y)-(a2.y-a1.y)*(b2.x-b1.x);
}double d(node a,node b){
return sqrt(sq(a.x-b.x)+sq(a.y-b.y));
}bool cmp(node p1,node p2){
double tmp=check(p1,p[1],p2,p[1]);
if(tmp>0)return 1;
else if(tmp==0&&d(p[0],p1)<d(p[0],p2))return 1;
return 0;
}
void add(double x,double y){
n++;
p[n].x=x,p[n].y=y;
if(p[n].y<p[1].y)swap(p[n],p[1]);
}
void deal(){
sort(p+2,p+1+n,cmp);
s[1]=p[1];cnt=1;
for(int i=2;i<=n;i++){
while(cnt>1&&check(s[cnt-1],s[cnt],s[cnt],p[i])<=0)
cnt--;
s[++cnt]=p[i];
}s[cnt+1]=p[1];
}
double C(){
double ans=0;
for(int i=1;i<=cnt;i++)
ans+=d(s[i],s[i+1]);
return ans;
}
};
数论
快速幂
template<class T>T ksm(T a,T b,T c){
T res=1;
while(b){
if(b&1)res=res*a%c;
a=a*a%c;b>>=1;
}return res;
}
逆元
template<class T>void exgcd(T a,T b,T &x,T &y){
if(!b)x=1,y=0;
else{
exgcd(b,a%b,x,y);
T t=x;x=y;
y=t-a/b*y;
}
}
template<class T>T inv(T a,T b){
T x,y;exgcd(a,b,x,y);
return (x%b+b)%b;
}
BSGS
template<class T>T bsgs(T a,T b,T p){
unordered_map<T,T>hash;
b%=p;T t=sqrt(p)+1;
for(T i=0;i<t;i++)
hash[b*ksm(a,i,p)%p]=i;
a=ksm(a,t,p);
if(!a)return b=0?1:-1;
for(T i=1;i<=t;i++){
T val=ksm(a,i,p);
int j=hash.find(val)==hash.end()?-1:hash[val];
if(j>=0&&i*t-j>=0)return i*t-j;
}return -1;
}
exBSGS
template<class T>T ex_bsgs(T a,T b,T p){
if(b==1||p==1)return -1;
T na=1,k=0;
while(T g=__gcd(a,p)){
if(g==1)break;
if(b%g)return -1;
k++;b/=g;p/=g;na=na*(a/g)%p;
if(na==b)return k;
}
long long f=bsgs(a,b*inv(na,p)%p,p);
if(f==-1)return -1;
return f+k;
}
数据结构
并查集
const int maxn=1e4+10;
struct DSU{
int fa[maxn];
DSU(){for(int i=1;i<maxn;i++)fa[i]=i;}
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
void merge(int x,int y){fa[getfa(y)]=getfa(x);}
};
可持久化线段树
struct node{
int l,r,lc,rc;int len,llen,rlen,mlen;
template<class T>node(T val){
if(val==1)llen=rlen=mlen=1;
else llen=rlen=mlen=0;
len=1;
}
node(){llen=rlen=mlen=len=0;}
node operator+(const node b)const{
node c;c.len=len+b.len;
if(r-l+1==mlen)c.llen=mlen+b.llen;
else c.llen=llen;
if(b.r-b.l+1==b.mlen)c.rlen=b.mlen+rlen;
else c.rlen=b.rlen;
c.mlen=max(rlen+b.llen,max(mlen,b.mlen));
return c;
}
void cpy(node from){
llen=from.llen;
rlen=from.rlen;
mlen=from.mlen;
len=from.len;
}
};
template<class A,class B>
struct HJT_Tree{
A t[maxn*20];B a[maxn];
B *operator[](const int x){return &a[x];}
int cnt;HJT_Tree(){cnt=0;}
int build(int l,int r){
int x=++cnt;
t[x].l=l,t[x].r=r;
if(l==r){
t[x].cpy(A(a[l]));
return x;
}
int mid=l+r>>1;
t[x].lc=build(l,mid);
t[x].rc=build(mid+1,r);
t[x].cpy(t[t[x].lc]+t[t[x].rc]);
return x;
}
int upd(int lst,int pos,B val){
int x=++cnt;t[x]=t[lst];
if(t[x].l==t[x].r){t[x].cpy(A(val));return x;}
int mid=t[x].l+t[x].r>>1;
if(pos<=mid)t[x].lc=upd(t[lst].lc,pos,val);
else t[x].rc=upd(t[lst].rc,pos,val);
t[x].cpy(t[t[x].lc]+t[t[x].rc]);
return x;
}
A qry(int x,int lq,int rq){
if(lq<=t[x].l&&t[x].r<=rq)return t[x];
int mid=t[x].l+t[x].r>>1;
if(rq<=mid)return qry(t[x].lc,lq,rq);
if(lq>mid)return qry(t[x].rc,lq,rq);
return qry(t[x].lc,lq,rq)+qry(t[x].rc,lq,rq);
}
};
HJT_Tree<node,int>Tree;
Splay
#define clear(x) {f[x]=key[x]=size[x]=recy[x]=son[x][0]=son[x][1]=0;}
#define get(x) (son[f[x]][1]==x)
#define connect(x,y,p) {if(x)f[x]=y;if(y)son[y][p]=x;}
#define update(x) {size[x]=recy[x];size[x]+=size[son[x][0]]+size[son[x][1]];}
template<const int N>
struct Splay{
int num,root,f[N],key[N],size[N],recy[N],son[N][2];
void rotate(int x){
int fa=f[x],ffa=f[fa],p1=get(x),p2=get(fa);
connect(son[x][p1^1],fa,p1);
connect(fa,x,p1^1);
connect(x,ffa,p2);
update(fa);update(x);
}
void splay(int x){
for(int fa;fa=f[x];rotate(x))
if(f[fa])rotate(get(x)==get(fa)?fa:x);
root=x;
}
void insert(int x){
if(!root){
root=++num;
key[root]=x;size[root]=recy[root]=1;
son[root][0]=son[root][1]=0;
return;
}
int now=root,fa=0;
while(1){
if(key[now]==x){
++recy[now];
update(now);update(fa);
splay(now);return;
}
fa=now,now=son[now][x>key[now]];
if(!now){
key[++num]=x;
size[num]=recy[num]=1;
f[num]=fa;son[fa][x>key[fa]]=num;
update(fa);splay(num);
return;
}
}
}
int find(int x){
int now=root,ans=0;
while(1){
if(x<key[now]){
now=son[now][0];
continue;
}
ans+=size[son[now][0]];
if(x==key[now]){splay(now);return ans+1;}
ans+=recy[now];now=son[now][1];
}
}
inline int kth(int x){
int now=root;
while(1){
if(son[now][0]&&x<=size[son[now][0]]){
now=son[now][0];
continue;
}
if(son[now][0])x-=size[son[now][0]];
if(x<=recy[now])return key[now];
x-=recy[now];now=son[now][1];
}
}
int pre(){
int now=son[root][0];
while(son[now][1])now=son[now][1];
return now;
}
int nxt(){
int now=son[root][1];
while(son[now][0])now=son[now][0];
return now;
}
void del(int x){
find(x);
if(recy[root]>1){
recy[root]--;
update(root);
return;
}
if(!son[root][0]&&!son[root][1]){
clear(root);root=0;
return;
}
int tmp=root;
if(!son[root][0]){
f[root=son[root][1]]=0;
clear(tmp);return;
}
if(!son[root][1]){
f[root=son[root][0]]=0;
clear(tmp);return;
}
int left=pre();
splay(left);connect(son[tmp][1],root,1);
clear(tmp);update(root);
}
};
可持久化平衡树
const int N=5e5+100;
namespace tree{
int n,rt[N],cnt;
struct node{
int ch[2];
int rnd,sz,v;
//rnd随机值,sz子节点的个数
//cnt节点的个数
}t[N*50];
int cpynode(int x){
t[++cnt]=t[x];
return cnt;
}
int newnode(int x){
t[++cnt].v=x;t[cnt].sz=1;
t[cnt].rnd=rand();return cnt;
}
#define ls(x) t[(x)].ch[0]
#define rs(x) t[(x)].ch[1]
void upd(int k){
if(k)
t[k].sz=t[ls(k)].sz+t[rs(k)].sz+1;
}
inline void split(int now,int k,int &x,int &y){
if(!now){x=0,y=0;return;}
if(t[now].v<=k){
x=cpynode(now);
split(rs(x),k,rs(x),y);
}else{
y=cpynode(now);
split(ls(y),k,x,ls(y));
}upd(x);upd(y);
}
inline int merge(int x,int y){
if(!x||!y)return x+y;//返回不为0的值
if(t[x].rnd<t[y].rnd){
int z=cpynode(x);
rs(z)=merge(rs(z),y);
upd(z);return z;
} else{
int z=cpynode(y);
ls(z)=merge(x,ls(z));
upd(z);return z;
}
}
inline void insert(int now,int k){
int x=0,y=0,z=0;
split(rt[now],k,x,y);
z=newnode(k);
rt[now]=merge(merge(x,z),y);
}
inline void del(int now,int k){
int x=0,y=0,z=0;
split(rt[now],k,x,y);//先把大于k的结点分离
split(x,k-1,x,z);//保证z中只有值为k的结点
z=merge(ls(z),rs(z));//若值为k的结点有多个,则合并后少一 个,如果原本只有一个或者没有,则返回0,相当于删除了值为k的点
rt[now]=merge(merge(x,z),y);//合并复原
}
inline int rnk(int now,int k){
int x=0,y=0;
split(rt[now],k-1,x,y);//以x为根的树中包含了所有值小于k的结点。
return t[x].sz+1;//结点数+1就是k的排名
}
inline int kth(int x,int k){
while(1){
if(t[ls(x)].sz+1==k)return t[x].v;
else if(t[ls(x)].sz>=k)x=ls(x);
else k-=t[ls(x)].sz+1,x=rs(x);
}
}
inline int pre(int now,int k){
int x=0,y=0,z=0;
split(rt[now],k-1,x,y);
if(!x)return -2147483647;
return kth(x,t[x].sz);
}
inline int suf(int now,int k){
int x=0,y=0,z=0;
split(rt[now],k,x,y);
if(!y)return 2147483647;
return kth(y,1);
}
}