模板
数学
组合数学
快速取模
#define ull unsigned long long
#define ui128 __uint128_t
struct Barrett{
ull d;ui128 m;
void init(ull _d){
d=_d,m=(((ui128)(1)<<64)/d);
}
}mod;
ull operator %(ull a,Barrett mod){
ull w=(mod.m*a)>>64;w=a-w*mod.d;
if(w>=mod.d)w-=mod.d;return w;
}
组合数
void init(){jc[0]=1;for(int i=1;i<N;i++) jc[i]=jc[i-1]*i%mod;}
ll ksm(ll a,ll b){ll ct=1;while(b){if(b&1) ct=ct*a%mod;b>>=1,a=a*a%mod;}return ct;}
ll C(ll n,ll m){return jc[n]*ksm(jc[n-m],mod-2)%mod*ksm(jc[m],mod-2)%mod;}
组合数 O(m)
ll ksm(ll a,ll b){ll ct=1;while(b){if(b&1) ct=ct*a%mod;b>>=1,a=a*a%mod;}return ct;}
ll C(ll n,ll m){
ll ct=1,t=1;if(n<m) return 0;
for(int i=1;i<=m;i++) (ct*=(n-i+1)%mod)%=mod,(t*=i)%=mod;
return ct*ksm(t,mod-2)%mod;
}
组合数(卡常)
ll ksm(ll a,ll b){ll ct=1;while(b){if(b&1) ct=ct*a%mod;b>>=1,a=a*a%mod;}return ct;}
ll C(ll m,ll n){return jc[n]*inv[m]%mod*inv[n-m]%mod;}
void init(){
jc[0]=1;
for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
inv[n]=ksm(jc[n],mod-2);
for(int i=N-11;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
逆元
for(ll i=2;i<=n;i++) dp[i]=(p-p/i)*dp[p%i]%p;
ksm+exgcd+BSGS
map<ll,ll> mp;
ll ksm(ll a,ll b,ll ct=1){while(b){if(b&1) ct=ct*a%p;a=a*a%p,b>>=1;}return ct;}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1,y=0;return a;}
ll t=exgcd(b,a%b,y,x);y-=a/b*x;return t;
}
void solve2(ll a,ll b,ll p){
ll t=exgcd(a,p,x,y);p/=t;
if(!(b%t)) cout<<((x*b/t)%p+p)%p<<"\n";
else cout<<"Orz, I cannot find x!\n";
}
void BS(ll a,ll b,ll p){for(int i=0;i<=m;i++) mp[b]=i,(b*=a)%=p;}
void GS(ll a,ll b,ll p,ll t=1){
if(!a&&!b){cout<<"1\n";return;}
if(!a){cout<<"Orz, I cannot find x!\n";return;}
ll ct=ksm(a,m);
for(int i=1;i<=m;i++)
if(mp[(t*=ct)%=p]){cout<<i*m-mp[t]<<"\n";return;}
cout<<"Orz, I cannot find x!\n";
}
void solve3(ll a,ll b,ll p){a%=p,b%=p,m=ceil(sqrt(p)),mp.clear(),BS(a,b,p),GS(a,b,p);}
线性代数
矩阵快速幂
struct MAT{
ll a[3][3]={};
ll* operator[](int x){return a[x];}
MAT operator*(MAT& b){
MAT res;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
for(int k=1;k<=2;k++)
(res[i][j]+=a[i][k]*b[k][j])%=mod;
return res;
}
}a,ans;
void ksm(ll b){while(b){if(b&1) ans=ans*a;a=a*a,b>>=1;}}
void init(){a[1][1]=a[1][2]=a[2][1]=ans[1][1]=ans[2][2]=1;}
ll get_ans(ll n){ksm(n);return ans[1][2];}
高斯消元
bool solve(){
for(int i=1;i<=n;i++){
ll r=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[j][i])>fabs(a[r][i])) r=j;
if(fabs(a[r][i])<eps) return 1;
if(r!=i) swap(a[i],a[r]);
double t=a[i][i];
for(int j=i;j<=n+1;j++) a[i][j]/=t;
for(int j=i+1;j<=n;j++){
t=a[j][i];
for(int k=i;k<=n+1;k++)
a[j][k]-=a[i][k]*t;
}
}
x[n]=a[n][n+1];
for(int i=n-1;i>=1;i--){
x[i]=a[i][n+1];
for(int j=i+1;j<=n;j++)
x[i]-=(a[i][j]*x[j]);
}
return 0;
}
矩阵求逆
void Gauss(){
for(int i=1,r;i<=n;i++){
r=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[j][i])>fabs(a[r][i])) r=j;
if(r!=i) swap(a[r],a[i]);
if(!a[i][i]){cout<<"No Solution";return;}
ll t=ksm(a[i][i],mod-2);
for(int j=1;j<=n;j++){
if(i==j) continue;
ll q=a[j][i]*t%mod;
for(int k=i;k<=(n<<1);k++)
a[j][k]-=a[i][k]*q,a[j][k]%=mod,a[j][k]+=mod,a[j][k]%=mod;
}
for(int j=1;j<=(n<<1);j++) a[i][j]*=t,a[i][j]%=mod;
}
for(int i=1;i<=n;i++)
for(int j=n+1;j<=(n<<1);j++)
cout<<a[i][j]<<(j==(n<<1)?"\n":" ");
}
void init(){for(int i=1;i<=n;i++) a[i][n+1]=1;}
数据结构
线段树家族
线段树 1
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (ls|1)
#define L ls,l,mid
#define R rs,mid+1,r
void up(ll rt){t[rt]=min(t[ls],t[rs]);}
void down(ll rt,ll k){t[rt]+=k,lazy[rt]+=k;}
void push_down(ll rt){if(lazy[rt]) down(ls,lazy[rt]),down(rs,lazy[rt]),lazy[rt]=0;}
void build(ll rt,ll l,ll r){if(l==r){t[rt]=a[l];return;}build(L),build(R),up(rt);}
void add(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){down(rt,k);return;}
push_down(rt),add(L,rl,rr,k),add(R,rl,rr,k),up(rt);
}
ll query(ll rt,ll l,ll r,ll rl,ll rr){
if(rl>r||rr<l) return 1e18;
if(rl<=l&&r<=rr) return t[rt];
push_down(rt);return min(query(L,rl,rr),query(R,rl,rr));
}
线段树 2
void up(ll rt){t[rt]=(t[rt<<1]+t[rt<<1|1])%mod;}
void build(ll rt,ll l,ll r){
lazy2[rt]=1;
if(l==r){t[rt]=a[l];return;}
ll mid=l+r>>1;
build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
up(rt);
}
void down(ll rt,ll l,ll r,ll k,ll k2){
(t[rt]*=k2)%=mod,(t[rt]+=k*(r-l+1)%mod)%=mod;
(lazy[rt]*=k2)%=mod,(lazy[rt]+=k)%=mod,(lazy2[rt]*=k2)%=mod;
}
void push_down(ll rt,ll l,ll mid,ll r){
down(rt<<1,l,mid,lazy[rt],lazy2[rt]);
down(rt<<1|1,mid+1,r,lazy[rt],lazy2[rt]);
lazy[rt]=0,lazy2[rt]=1;
}
void update(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){(t[rt]+=(r-l+1)*k)%=mod,(lazy[rt]+=k)%=mod;return;}
ll mid=l+r>>1;push_down(rt,l,mid,r);
update(rt<<1,l,mid,rl,rr,k),update(rt<<1|1,mid+1,r,rl,rr,k);
up(rt);
}
void update2(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){(t[rt]*=k)%=mod,(lazy[rt]*=k)%=mod,(lazy2[rt]*=k)%=mod;return;}
ll mid=l+r>>1;push_down(rt,l,mid,r);
update2(rt<<1,l,mid,rl,rr,k),update2(rt<<1|1,mid+1,r,rl,rr,k);
up(rt);
}
ll query(ll rt,ll l,ll r,ll rl,ll rr){
if(rl>r||rr<l) return 0;
if(rl<=l&&r<=rr) return t[rt];
ll mid=l+r>>1;push_down(rt,l,mid,r);
return (query(rt<<1,l,mid,rl,rr)+query(rt<<1|1,mid+1,r,rl,rr))%mod;
}
动态开点线段树
struct Tree{ll ls,rs,val,lazy=-1;}t[N];
void up(ll rt){t[rt].val=t[t[rt].ls].val+t[t[rt].rs].val;}
void down(ll rt,ll l,ll r,ll k){t[rt].lazy=k,t[rt].val=(r-l+1)*k;}
void push_down(ll rt,ll l,ll mid,ll r){
if(!~t[rt].lazy) return;
down(t[rt].ls,l,mid,t[rt].lazy);
down(t[rt].rs,mid+1,r,t[rt].lazy);
t[rt].lazy=-1;
}
void update(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rr<l||r<rl) return;
if(rl<=l&&r<=rr){down(rt,l,r,k);return;}
if(!t[rt].ls) t[rt].ls=++ct;
if(!t[rt].rs) t[rt].rs=++ct;
ll mid=l+r>>1;push_down(rt,l,mid,r);
update(t[rt].ls,l,mid,rl,rr,k);update(t[rt].rs,mid+1,r,rl,rr,k);
up(rt);
}
线段树-区间加 区间求 gcd
void up(ll rt){t[rt]=__gcd(t[rt<<1],t[rt<<1|1]),s[rt]=s[rt<<1]+s[rt<<1|1];}
void build(ll rt,ll l,ll r){
if(l==r){t[rt]=s[rt]=a[l]-a[l-1];return;}
ll mid=l+r>>1;
build(rt<<1,l,mid),build(rt<<1|1,mid+1,r),up(rt);
}
void update(ll rt,ll l,ll r,ll x,ll d){
if(l>x||r<x) return;
if(l==r){t[rt]+=d,s[rt]+=d;return;}
ll mid=l+r>>1;
update(rt<<1,l,mid,x,d),update(rt<<1|1,mid+1,r,x,d),up(rt);
}
ll query(ll rt,ll l,ll r,ll rl,ll rr){
if(rl>r||rr<l) return 0;
if(rl<=l&&r<=rr) return t[rt];
ll mid=l+r>>1;
return __gcd(query(rt<<1,l,mid,rl,rr),query(rt<<1|1,mid+1,r,rl,rr));
}
ll sum(ll rt,ll l,ll r,ll rl,ll rr){
if(rl>r||rr<l) return 0;
if(rl<=l&&r<=rr) return s[rt];
ll mid=l+r>>1;
return sum(rt<<1,l,mid,rl,rr)+sum(rt<<1|1,mid+1,r,rl,rr);
}
void upd(ll l,ll r,ll d){update(1,1,n,l,d),update(1,1,n,r+1,-d);}
ll qry(ll l,ll r){return abs(__gcd(query(1,1,n,l+1,r),sum(1,1,n,1,l)));}
线段树-区间赋值 区间覆盖 区间求和
void up(ll rt){t[rt]=t[rt<<1]+t[rt<<1|1];}
void push_down(ll rt,ll l,ll mid,ll r){
if(~lazy2[rt]){
t[rt<<1]=lazy2[rt]*(mid-l+1);
t[rt<<1|1]=lazy2[rt]*(r-mid);
lazy2[rt<<1]=lazy2[rt<<1|1]=lazy2[rt];
lazy[rt<<1]=lazy[rt<<1|1]=0;
lazy2[rt]=-1;
}
if(lazy[rt]){
lazy[rt<<1]^=1;
lazy[rt<<1|1]^=1;
t[rt<<1]=mid-l+1-t[rt<<1];
t[rt<<1|1]=r-mid-t[rt<<1|1];
lazy[rt]=0;
}
}
void update(ll rt,ll l,ll r,ll rl,ll rr){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){lazy[rt]^=1;t[rt]=r-l+1-t[rt];return;}
ll mid=l+r>>1;push_down(rt,l,mid,r);
update(rt<<1,l,mid,rl,rr),update(rt<<1|1,mid+1,r,rl,rr);
up(rt);
}
void cover(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){t[rt]=(r-l+1)*k;lazy2[rt]=k,lazy[rt]=0;return;}
ll mid=l+r>>1;push_down(rt,l,mid,r);
cover(rt<<1,l,mid,rl,rr,k),cover(rt<<1|1,mid+1,r,rl,rr,k);
up(rt);
}
ll query(ll rt,ll l,ll r){
if(l==r) return l;
ll mid=l+r>>1;push_down(rt,l,mid,r);
if(t[rt<<1]<mid-l+1) return query(rt<<1,l,mid);
return query(rt<<1|1,mid+1,r);
}
void init(){memset(lazy2,-1,sizeof lazy2);}
线段树分治
void init(){for(int i=1;i<=n*2;i++) fa[i]=i,sz[i]=1;}
ll getfa(ll x){return fa[x]==x?x:getfa(fa[x]);}
void hb(ll x,ll y){
ll fx=getfa(x),fy=getfa(y);
if(fx==fy) return;
if(sz[fx]>sz[fy]) fx^=fy^=fx^=fy;
s.push({fx,sz[fx]==sz[fy]});fa[fx]=fy,sz[fy]+=(sz[fx]==sz[fy]);
}
void update(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){t[rt].push_back(k);return;}
ll mid=l+r>>1;
update(rt<<1,l,mid,rl,rr,k),update(rt<<1|1,mid+1,r,rl,rr,k);
}
void dfs(ll rt,ll l,ll r){
bool flag=1;ll mid=l+r>>1,lst=s.size();
for(auto i:t[rt]){
ll fx=getfa(x[i]),fy=getfa(y[i]);
if(fx==fy){
for(int i=l;i<=r;i++) cout<<"No\n";
flag=0;
break;
}
hb(x[i],y[i]+n),hb(y[i],x[i]+n);
}
if(flag){
if(l==r) cout<<"Yes\n";
else dfs(rt<<1,l,mid),dfs(rt<<1|1,mid+1,r);
}
while(s.size()>lst) sz[fa[s.top().fi]]-=s.top().se,fa[s.top().fi]=s.top().fi,s.pop();
}
线段树优化建图
void Add(ll x,ll y,ll w=0){e[x].pb(y,(~w?w:0));if(!~w) Add(y,x);}
void build(ll rt,ll l,ll r){
if(l==r){leaf[l]=rt;return;}
ll mid=l+r>>1;
Add(rt,rt<<1),Add(rt,rt<<1|1);
Add((rt<<1)+P,rt+P),Add((rt<<1|1)+P,rt+P);
build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
}
void add(ll rt,ll l,ll r,ll rl,ll rr,ll v,ll w,ll op){
if(rl>r||rr<l) return;
if(rl<=l&&r<=rr){
if(op) Add(rt+P,v,w);
else Add(v,rt,w);
return;
}
ll mid=l+r>>1;
add(rt<<1,l,mid,rl,rr,v,w,op),add(rt<<1|1,mid+1,r,rl,rr,v,w,op);
}
void dijkstra(){
priority_queue<pii,vector<pii>,greater<pii> > q;
memset(dis,0x3f,sizeof dis);
q.push({dis[leaf[s]+P]=0,leaf[s]+P});
while(!q.empty()){
ll x=q.top().se;q.pop();
if(vis[x]) continue;
vis[x]=1;
for(auto p:e[x]){
ll y=p.fi,w=p.se;
if(dis[y]>dis[x]+w) q.push({dis[y]=dis[x]+w,y});
}
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>q>>s;build(1,1,n);
while(q--){
cin>>op>>v;
if(op==1) cin>>u>>w,Add(leaf[v],leaf[u],w);
else cin>>l>>r>>w,add(1,1,n,l,r,leaf[v],w,op&1);
}
for(int i=1;i<=n;i++) Add(leaf[i],leaf[i]+P,-1);
dijkstra();
for(int i=1;i<=n;i++) cout<<(dis[leaf[i]]==inf?-1:dis[leaf[i]])<<" ";
return 0;
}
扫描线
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (ls|1)
#define L ls,l,mid
#define R rs,mid,r
// 上一行注意!
struct P{ll h,x,y,op;bool operator<(const P& b){return h==b.h?x>b.x:h<b.h;}}p[N];
struct Q{ll s,l;}tree[N];// 开大一点!!!
void up(ll rt,ll l,ll r){
if(tree[rt].s>0) tree[rt].l=y[r]-y[l];
else tree[rt].l=tree[ls].l+tree[rs].l;
}
void change(ll rt,ll l,ll r,ll rl,ll rr,ll k){
if(rl>=y[r]||y[l]>=rr) return;
if(rl<=y[l]&&y[r]<=rr){tree[rt].s+=k,up(rt,l,r);return;}
change(L,rl,rr,k),change(R,rl,rr,k),up(rt,l,r);
}
void solve(){
cin>>n;n<<=1;
for(int i=1;i<n;i+=2){
cin>>sx>>sy>>ex>>ey;
p[i]={sx,sy,ey,1},p[i+1]={ex,sy,ey,-1};
y[i]=sy,y[i+1]=ey;
}
sort(y+1,y+n+1),sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
if(y[i]!=y[i+1]) y[++ct]=y[i];
for(int i=1;i<n;i++)
change(1,1,ct,p[i].x,p[i].y,p[i].op),ans+=(p[i+1].h-p[i].h)*tree[1].l;
cout<<ans;
}
树状数组 1
#define lowbit(x) (x)&(-(x))
void xg(ll x,ll k){while(x<=n) s[x]+=k,x+=lowbit(x);}
ll sum(ll x,ll ct=0){while(x) ct+=s[x],x-=lowbit(x);return ct;}
ll getsum(ll l,ll r){return sum(r)-sum(l-1);}
树状数组 2
void xg(ll s[],ll x,ll k){while(x<=n) s[x]+=k,x+=lowbit(x);}
void qxg(ll x,ll y,ll k){xg(s,x,k);xg(s,y+1,-k);xg(s2,x,x*k);xg(s2,y+1,-(y+1)*k);}
ll sum(ll s[],ll x,ll ct=0){while(x) ct+=s[x],x-=lowbit(x);return ct;}
ll getsum(ll l,ll r){return (r+1)*sum(s,r)-sum(s2,r)-l*sum(s,l-1)+sum(s2,l-1);}
平衡树(数组版)
ll New(ll x){val[++ct]=x,da[ct]=rand(),sz[ct]=cnt[ct]=1;return ct;}
void up(ll rt){sz[rt]=sz[son[rt][0]]+sz[son[rt][1]]+cnt[rt];}
void build(){root=New(-inf),son[root][1]=New(inf),up(root);}
void ro(ll &rt,bool d){// rotate
ll t=son[rt][!d];son[rt][!d]=son[t][d],son[t][d]=rt,rt=t;
up(son[rt][d]),up(rt);
}
void in(ll &rt,ll x){// insert
if(!rt){rt=New(x);return;}
if(val[rt]==x){cnt[rt]++,up(rt);return;}
bool d=(x>val[rt]);in(son[rt][d],x);
if(da[rt]<da[son[rt][d]]) ro(rt,!d);
up(rt);
}
void de(ll &rt,ll x){// delete
if(!rt) return;
if(val[rt]==x){
if(cnt[rt]>1){cnt[rt]--;up(rt);return;}
if(son[rt][0]||son[rt][1]){
if(!son[rt][1]||da[son[rt][0]]>da[son[rt][1]]) ro(rt,1),de(son[rt][1],x);
else ro(rt,0),de(son[rt][0],x);
up(rt);
}else rt=0;
return;
}
if(x<val[rt]) de(son[rt][0],x);
else de(son[rt][1],x);
up(rt);
}
ll ra(ll rt,ll x){// rank
if(!rt) return 1;
if(val[rt]==x) return sz[son[rt][0]]+1;
if(val[rt]>x) return ra(son[rt][0],x);
return sz[son[rt][0]]+cnt[rt]+ra(son[rt][1],x);
}
ll se(ll rt,ll x){// search
if(!rt) return inf;
if(x<=sz[son[rt][0]]) return se(son[rt][0],x);
if(x<=sz[son[rt][0]]+cnt[rt]) return val[rt];
return se(son[rt][1],x-sz[son[rt][0]]-cnt[rt]);
}
ll pr(ll x){// pre
ll rt=root,p=0;
while(rt)
if(val[rt]<x) p=val[rt],rt=son[rt][1];
else rt=son[rt][0];
return p;
}
ll ne(ll x){// next
ll rt=root,p=0;
while(rt)
if(val[rt]>x) p=val[rt],rt=son[rt][0];
else rt=son[rt][1];
return p;
}
平衡树(结构体版)
#define ls t[rt].son[0]
#define rs t[rt].son[1]
struct T{ll val,data,sz,cnt,son[2];}t[N];
ll New(ll x){t[++ct].val=x,t[ct].data=rand(),t[ct].sz=t[ct].cnt=1;return ct;}
void up(ll rt){t[rt].sz=t[ls].sz+t[rs].sz+t[rt].cnt;}
void rot(ll &rt,bool d){
int p=t[rt].son[!d];t[rt].son[!d]=t[p].son[d],t[p].son[d]=rt,rt=p;
up(t[rt].son[d]),up(rt);
}
void insert(ll &rt,ll x){
if(!rt){rt=New(x);return;}
if(t[rt].val==x){t[rt].cnt++,up(rt);return;}
bool d=(x>t[rt].val);insert(t[rt].son[d],x);
if(t[rt].data<t[t[rt].son[d]].data) rot(rt,!d);
up(rt);
}
void del(ll &rt,ll x){
if(!rt) return;
if(t[rt].val==x){
if(t[rt].cnt>1){t[rt].cnt--;up(rt);return;}
if(ls||rs){
if(!rs||t[ls].data>t[rs].data) rot(rt,1),del(rs,x);
else rot(rt,0),del(ls,x);
up(rt);
}else rt=0;
return;
}
if(x<t[rt].val) del(ls,x);
else del(rs,x);
up(rt);
}
ll rnk(ll rt,ll x){
if(!rt) return 1;
if(t[rt].val==x) return t[ls].sz+1;
if(t[rt].val>x) return rnk(ls,x);
return t[ls].sz+t[rt].cnt+rnk(rs,x);
}
ll search(ll rt,ll x){
if(!rt) return inf;
if(x<=t[ls].sz) return search(ls,x);
if(x<=t[ls].sz+t[rt].cnt) return t[rt].val;
return search(rs,x-t[ls].sz-t[rt].cnt);
}
ll pre(ll x){
ll rt=root,p=0;
while(rt)
if(t[rt].val<x) p=t[rt].val,rt=rs;
else rt=ls;
return p;
}
ll nxt(ll x){
ll rt=root,p=0;
while(rt)
if(t[rt].val>x) p=t[rt].val,rt=ls;
else rt=rs;
return p;
}
主席树
#define mid (l+r>>1)
ll n,m,p,l,r,k,ct,a[N],b[N],rt[N];
struct T{ll ls,rs,val;}t[N<<5];
ll build(ll l,ll r){
ll rt=++ct;if(l==r) return rt;
t[rt].ls=build(l,mid),t[rt].rs=build(mid+1,r);
return rt;
}
ll mk(ll x){t[++ct]=t[x];return ct;}
ll update(ll rt,ll l,ll r,ll x){
if(l>x||r<x) return rt;
rt=mk(rt),t[rt].val++;
if(l==r) return rt;
t[rt].ls=update(t[rt].ls,l,mid,x),t[rt].rs=update(t[rt].rs,mid+1,r,x);
return rt;
}
ll query(ll rt,ll rt2,ll l,ll r,ll x){
if(l==r) return l;
ll tmp=t[t[rt2].ls].val-t[t[rt].ls].val;
if(x<=tmp) return query(t[rt].ls,t[rt2].ls,l,mid,x);
return query(t[rt].rs,t[rt2].rs,mid+1,r,x-tmp);
}
void init(){
for(int i=1;i<=n;i++) b[i]=a[i];
sort(b+1,b+n+1);p=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+p+1,a[i])-b;
rt[0]=build(1,p);for(int i=1;i<=n;i++) rt[i]=update(rt[i-1],1,p,a[i]);
}
ll qry(ll l,ll r){return b[query(rt[l-1],rt[r],1,p,k)];}
暴力数据结构
带修莫队
struct Q{
ll x,y,i,pos,posy,t;
bool operator<(const Q& B){return pos!=B.pos?pos<B.pos:(posy!=B.posy?posy<B.posy:t<B.t);}
}q[N],g[N];
void add(ll x){res+=!cnt[x]++;}
void del(ll x){res-=!--cnt[x];}
void Mo(ll x,ll y){
while(l>x) add(a[--l]);
while(r<y) add(a[++r]);
while(l<x) del(a[l++]);
while(r>y) del(a[r--]);
}
void up(ll x,ll y,ll t){
if(x<=g[t].x&&g[t].x<=y) del(a[g[t].x]),add(g[t].y);
swap(a[g[t].x],g[t].y);
}
void xg(ll k,ll x,ll y){
while(t<k) up(x,y,++t);
while(t>k) up(x,y,t--);
}
其他
st 表
void init(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
ll query(ll l,ll r){
ll k=log2(r-l+1);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
Trie
void insert(string s){
ll x=0;
for(auto c:s){
if(!trie[x][c]) trie[x][c]=++ct;
x=trie[x][c],tot[x]++;
}
}
ll query(string s){
ll x=0;
for(auto c:s){
if(!trie[x][c]) return 0;
x=trie[x][c];
}
return tot[x];
}
void init(){
for(int i=0;i<=ct;i++)
for(int j=0;j<128;j++) trie[i][j]=0;
for(int i=0;i<=ct;i++) tot[i]=0;
ct=0;
}
笛卡尔树
void build(){
s[1]=top=1;
for(int i=2;i<=n;i++){
while(top&&a[i]<a[s[top]]) top--;
if(!top) ls[i]=s[1];
else ls[i]=rs[s[top]],rs[s[top]]=i;
s[++top]=i;
}
}
图论/树论
tarjan 系列
缩点
void tarjan(ll x){
dfn[x]=low[x]=++ct,s[++top]=x,vis[x]=1;
for(auto y:e[x]){
if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
tot++;
while(s[top+1]!=x) belong[s[top]]=tot,vis[s[top--]]=0;
}
}
割点
void tarjan(ll x,ll fa,ll rt){
dfn[x]=low[x]=++ct;ll s=0;
for(auto y:e[x]){
if(y==fa) continue;
if(!dfn[y]){
s++;tarjan(y,x,rt);low[x]=min(low[x],low[y]);
if(x!=rt&&low[y]>=dfn[x]) ans+=!ok[x],ok[x]=1;
}else if(dfn[y]<dfn[x]) low[x]=min(low[x],dfn[y]);
}
if(x==rt&&s>=2) ans+=!ok[x],ok[x]=1;
}
点双
void tarjan(ll x,ll fa,ll rt){
low[x]=dfn[x]=++ct;
ll son=0;s[++top]=x;
for(auto y:e[x])
if(!dfn[y]){
son++,tarjan(y,x,rt),low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){
ans++;
do{
p[ans].pb(s[top--]);
}while(s[top+1]!=y);
p[ans].pb(x);
}
}else if(dfn[y]<dfn[x]&&y!=fa) low[x]=min(low[x],dfn[y]);
if(x==rt&&!son) p[++ans].pb(x);
}
边双
void tarjan(ll x,ll fa){
s[++top]=x,dfn[x]=low[x]=(++ct);
for(int i=h[x];i;i=nxt[i]){
if((~fa)&&i==(fa^1)) continue;
if(!dfn[to[i]]) tarjan(to[i],i),low[x]=min(low[x],low[to[i]]);
else low[x]=min(low[x],dfn[to[i]]);
}
if(dfn[x]==low[x]){
tot++;
while(s[top+1]!=x) p[tot].push_back(s[top--]);
}
}
其他
dijkstra
void dijkstra(ll s){
priority_queue<pii,vector<pii>,greater<pii> > q;
memset(dis,0x3f,sizeof dis);q.push({dis[s]=0,s});
while(!q.empty()){
ll x=q.top().se;q.pop();
if(vis[x]) continue;vis[x]=1;
for(auto p:e[x]){
ll y=p.fi,w=p.se;
if(dis[y]>dis[x]+w) q.push({dis[y]=dis[x]+w,y});
}
}
}
kruskal
struct P{ll x,y,w;bool operator<(const P& B){return w<B.w;}}e[N];
ll getfa(ll x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
bool hb(ll x,ll y){x=getfa(x),y=getfa(y);if(x!=y){fa[x]=y;return 1;}return 0;}
void kruskal(){
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++) if(hb(e[i].x,e[i].y)) ans+=e[i].w;
}
lca
void dfs(ll x,ll fa){
d[x]=d[fa]+1,f[x][0]=fa;
for(int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
for(auto y:e[x]) if(y!=fa) dfs(y,x);
}
ll lca(ll x,ll y){
if(d[x]<d[y]) swap(x,y);
for(int i=20;~i;i--) if(d[f[x][i]]>=d[y]) x=f[x][i];
if(x==y) return x;
for(int i=20;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
lca(树剖版)
void dfs(ll x){
sz[x]=1,d[x]=d[f[x]]+1;
for(auto y:e[x]) if(y!=f[x]) f[y]=x,dfs(y),sz[x]+=sz[y];
}
void dfs1(ll x){
ll t=0;
if(!top[x]) top[x]=x;
for(auto y:e[x]) if(y!=f[x]&&sz[y]>sz[t]) t=y;
if(t) top[t]=top[x],dfs1(t);
for(auto y:e[x]) if(y!=f[x]&&t!=y) dfs1(y);
}
ll lca(ll x,ll y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) x^=y^=x^=y;
x=f[top[x]];
}
if(d[x]>d[y]) x^=y^=x^=y;
return x;
}
树剖(树状数组)
void xg(ll s[],ll x,ll k){while(x<=n) s[x]+=k,s[x]%=p,x+=lowbit(x);}
void qxg(ll x,ll y,ll k){
xg(s,x,k);xg(s,y+1,-k);
xg(s2,x,x*k);xg(s2,y+1,-(y+1)*k);
}
ll sum(ll s[],ll x){
ll ct=0;
while(x) ct+=s[x],ct%=p,x-=lowbit(x);
return ct;
}
ll query(ll l,ll r){return (((r+1)*sum(s,r)%p-sum(s2,r)-l*sum(s,l-1)%p+sum(s2,l-1))%p+p)%p;}
void add(ll x,ll y){e[x].pb(y),e[y].pb(x);}
void dfs(ll x,ll f){
fa[x]=f,sz[x]=1,d[x]=d[f]+1;
for(auto y:e[x]) if(y!=f) dfs(y,x),sz[x]+=sz[y],son[x]=(sz[y]>sz[son[x]]?y:son[x]);
}
void dfs2(ll x,ll f){
top[x]=f,id[x]=++ct;
if(w[x]) qxg(id[x],id[x],w[x]);
if(!son[x]) return;
dfs2(son[x],f);
for(auto y:e[x]) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
void addp(ll x,ll y,ll k){
k%=p;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) x^=y^=x^=y;
qxg(id[top[x]],id[x],k),x=fa[top[x]];
}
if(d[x]>d[y]) x^=y^=x^=y;
qxg(id[x],id[y],k);
}
void adds(ll x,ll k){qxg(id[x],id[x]+sz[x]-1,k%p);}
ll queryp(ll x,ll y){
ll res=0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) x^=y^=x^=y;
res+=query(id[top[x]],id[x]),res%=p,x=fa[top[x]];
}
if(d[x]>d[y]) x^=y^=x^=y;
res+=query(id[x],id[y]),res%=p;
return res;
}
ll querys(ll x){return query(id[x],id[x]+sz[x]-1);}
长链剖分
void dfs(ll x,ll fa){
d[x]=d[fa]+1;
for(auto y:e[x]) if(y!=fa) dfs(y,x);
rt=(d[rt]<d[x]?x:rt);
}
void dfs2(ll x,ll fa){
for(auto y:e[x]) if(y!=fa) dfs2(y,x),son[x]=(f[son[x]]>f[y]?son[x]:y);
f[x]=f[son[x]]+1;
for(auto y:e[x]) if(y!=fa&&y!=son[x]) chain.pb(f[y]);
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<n;i++) cin>>x>>y,e[x].pb(y),e[y].pb(x);
dfs(1,0);dfs2(rt,0),chain.pb(f[rt]);
sort(chain.begin(),chain.end(),greater<ll>());
for(int i=2;i<=n&&i-2<chain.size();i++) ans[i]=ans[i-1]+chain[i-2];
for(int i=chain.size()+2;i<=n;i++) ans[i]=ans[i-1];
ans[1]=1;
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
return 0;
}
Prüfer 序列
void prufer(){
ll x=0,leaf=0;
for(int i=1;i<=n;i++) if(!d[i]){x=leaf=i;break;}
for(int i=1;i<n-1;i++){
p[i]=fa[leaf];
if(!--d[fa[leaf]]&&fa[leaf]<x) leaf=fa[leaf];
else{while(d[++x]);leaf=x;}
}
}
void get_prufer(){
ll x=0,leaf=0;while(d[++x]);leaf=x;
for(int i=1;i<n-1;i++){
fa[leaf]=p[i];
if(!--d[fa[leaf]]&&fa[leaf]<x) leaf=fa[leaf];
else{while(d[++x]);leaf=x;}
}
fa[leaf]=n;
}
点分治
void getrt(ll x,ll fa,ll n){
sz[x]=1,mx[x]=0;
for(auto p:e[x]) if(p.fi!=fa&&!vis[p.fi]) getrt(p.fi,x,n),mx[x]=max(mx[x],sz[p.fi]),sz[x]+=sz[p.fi];
mx[x]=max(mx[x],n-sz[x]);
if(!rt||mx[x]<mx[rt]) rt=x;
}
void init(ll x,ll fa){
if(d[x]<M) t.pb(d[x]);
for(auto p:e[x]) if(p.fi!=fa&&!vis[p.fi]) d[p.fi]=d[x]+p.se,init(p.fi,x);
}
void calc(ll x){
all.clear();
for(auto p:e[x])
if(!vis[p.fi]){
t.clear(),d[p.fi]=p.se,init(p.fi,x);
for(int i=1;i<=m;i++) if(!ans[i]) for(auto l:t) if(q[i]>=l&&ok[q[i]-l]){ans[i]=1;break;}
for(auto l:t) ok[l]=1,all.pb(l);
}
for(auto l:all) ok[l]=0;
}
void solve(ll x){
vis[x]=ok[0]=1;calc(x);
for(auto p:e[x]) if(!vis[p.fi]) rt=0,getrt(p.fi,x,sz[p.fi]),solve(rt);
}
void treediv(){getrt(1,0,n);getrt(rt,0,n);solve(rt);}
计算几何
极角排序
#define double long double
const ll N=1e5+10;
const double pi=acos(-1);
ll n,ans1,ans2;
double ans;
struct P{
double x,y,a;ll i;
bool operator<(const P& b){return a<b.a;}
}p[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y,p[i].i=i,p[i].a=atan2(p[i].y,p[i].x),p[i].a+=(p[i].a<0?pi*2.:0.);
sort(p+1,p+n+1);ans=p[1].a-p[n].a+pi*2.;ans1=p[1].i;ans2=p[n].i;
for(int i=2;i<=n;i++) if(p[i].a-p[i-1].a<ans) ans=p[i].a-p[i-1].a,ans2=p[i].i,ans1=p[i-1].i;
cout<<ans1<<" "<<ans2;
}
凸包
struct P{
double x,y;
bool operator<(const P& B)const{return x!=B.x?x<B.x:y<B.y;}
}a[N],s[N];
double K(P L,P R){return L.x!=R.x?(L.y-R.y)/(L.x-R.x):1e18;}
double dis(P L,P R){return sqrt((L.x-R.x)*(L.x-R.x)+(L.y-R.y)*(L.y-R.y));}
void solve(){
top=0;
for(int i=1;i<=n;i++){
s[++top]=a[i];
while(top>2&&K(s[top-2],s[top])<K(s[top-2],s[top-1])) s[top-1]=s[top],top--;
}
for(int i=1;i<top;i++) ans+=dis(s[i],s[i+1]);
}
void tubao(){
sort(a+1,a+n+1);solve();
reverse(a+1,a+n+1);solve();
}
字符串
kmp
void init(){
for(int i=2,j=0;i<=m;i++){
while(j&&b[i]!=b[j+1]) j=nxt[j];
nxt[i]=(j+=(b[i]==b[j+1]));
}
}
void kmp(){
for(int i=1,j=0;i<=n;i++){
while(j&&a[i]!=b[j+1]) j=nxt[j];
if(a[i]==b[j+1]) j++;
if(j==m) cout<<i-m+1<<"\n",j=nxt[j];
}
}
网络流
网络最大流
void add(ll u,ll v,ll w){e[++ct]={v,h[u],w},h[u]=ct;}
bool bfs(){
for(int i=1;i<=n;i++) dis[i]=inf;
queue<ll> q;
q.push(s);dis[s]=0,now[s]=h[s];
while(!q.empty()){
ll x=q.front();q.pop();
for(int i=h[x];i;i=e[i].nxt)
if(e[i].w>0&&dis[e[i].to]==inf){
q.push(e[i].to);dis[e[i].to]=dis[x]+1,now[e[i].to]=h[e[i].to];
if(e[i].to==t) return 1;
}
}
return 0;
}
ll dfs(ll x,ll v){
if(x==t) return v;
ll res=0,k=0;
for(int i=now[x];i&&v;i=e[i].nxt){
now[x]=i;
if(e[i].w>0&&dis[e[i].to]==dis[x]+1){
k=dfs(e[i].to,min(v,e[i].w));
if(!k) dis[e[i].to]=inf;
e[i].w-=k,e[i^1].w+=k;
res+=k,v-=k;
}
}
return res;
}
ll Dinic(){
ll ans=0;
while(bfs()) ans+=dfs(s,inf);
return ans;
}
卡常
快读快写
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(c=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x*f;
}
void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
火车头
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
以颤抖之身追赶,怀敬畏之心挑战。--《棋魂》