깃허브에 올리고 싶었지만 깃허브는 너무 어렵다. (상시 수정합니다.) (재정리가 필요해보인다.)
1. Segment Tree
구현체는 간단하나 응용이 어렵다는 생각이 듦. 구현 복잡하고 응용 다양한 코드는 제출코드 참고.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll arr[1<<21],sz=1;
void update(int i,ll val)
{
for(arr[i+=sz]=val;i>1;i>>=1) arr[i>>1]=arr[i]+arr[i^1];
}
ll sum(int l,int r)
{
ll res=0;
for(l+=sz,r+=sz+1;l<r;l>>=1,r>>=1){
if(l&1) res+=arr[l++];
if(r&1) res+=arr[--r];
}
return res;
}
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int q=m+k;
sz=1<<(int)ceil(log2(n));
for(int i=0;i<n;i++) scanf("%lld",&arr[sz+i]);
for(int i=sz-1;i>=1;i--) arr[i]=arr[i<<1]+arr[i<<1|1];
while(q--){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
if(a==1) update(b-1,c);
else printf("%lld\n",sum(b-1,c-1));
}
}
2. Sieve of Eratosthenes
bool np[1000001];
np[0]=np[1]=true;
for(ll i=2;i<=n;i++) if(!np[i]) for(ll j=i*i;j<=n;j+=i) np[j]=true;
3. factorial inverse O(N+logP) for nCr
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int fac[1000001],inv[1000001];
int fpow(int x,int y)
{
int res=1;
while(y){
if(y&1) res=1LL*res*x%mod;
x=1LL*x*x%mod;
y>>=1;
}
return res;
}
int C(int n,int r)
{
return 1LL*fac[n]*inv[r]%mod*inv[n-r]%mod;
}
int main()
{
int n,r;
scanf("%d%d",&n,&r);
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;
inv[n]=fpow(fac[n],mod-2);
for(int i=n-1;i>0;i--) inv[i]=1LL*inv[i+1]*(i+1)%mod;
printf("%d",C(n,r));
}
4. mobius_inversion
int mu[50001];
void make_mu()
{
mu[1]=1;
for(int i=1;i<=50000;i++)
for(int j=2*i;j<=50000;j+=i) mu[j]-=mu[i];
}
x의 약수 중 제곱수 존재: mu[x]=0
x의 소인수 (2*k)개: mu[x]=1
x의 소인수 (2*k+1)개: mu[x]=-1
5. LIS O(NlogN)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,ans=0;
vector<int> v;
v.push_back(0);
scanf("%d",&n);
while(n--){
int x;
scanf("%d",&x);
if(x>v.back()){
v.push_back(x);
ans++;
}
else v[lower_bound(v.begin(),v.end(),x)-v.begin()]=x;
}
printf("%d",ans);
}
6. 기하 테크닉
7. 다익스트라
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
typedef pair<int,int> pii;
const int INF=987654321;
int main()
{
int v,e,st;
vector<pii> ad[20005];
scanf("%d%d%d",&v,&e,&st);
for(int i=0;i<e;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
ad[a].push_back({c,b});
}
vector<int> d(v+1);
fill(d.begin(),d.end(),INF);
priority_queue<pii,vector<pii>,greater<pii>> pq;
pq.push({0,st});
d[st]=0;
while(!pq.empty()){
int dist=pq.top().X;
int idx=pq.top().Y;
pq.pop();
if(d[idx]!=dist) continue;
for(int i=0;i<ad[idx].size();i++){
int cost=ad[idx][i].X;
int nidx=ad[idx][i].Y;
if(d[nidx]>dist+cost){
d[nidx]=dist+cost;
pq.push({d[nidx],nidx});
}
}
}
for(int i=1;i<=v;i++){
if(d[i]==INF) puts("INF");
else printf("%d\n",d[i]);
}
}
8. GCD
ll gcd(ll a,ll b)
{
for(;b;a%=b,swap(a,b));
return a;
}
9. Convex Hull
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
typedef pair<int,int> pii;
typedef long long ll;
vector<pii> d;
int ccw(pii a,pii b,pii c)
{
ll res=1LL*(b.X-a.X)*(c.Y-a.Y)-1LL*(b.Y-a.Y)*(c.X-a.X);
return res>0?1:res<0?-1:0;
}
bool cmp(pii a,pii b)
{
int res=ccw(d[0],a,b);
return res?res>0:a<b;
}
int main()
{
int n;
scanf("%d",&n);
d.resize(n);
for(int i=0;i<n;i++){
scanf("%d%d",&d[i].X,&d[i].Y);
if(d[0]>d[i]) swap(d[0],d[i]);
}
sort(d.begin()+1,d.end(),cmp);
vector<pii> ch; // maybe stack
ch.push_back(d[0]),ch.push_back(d[1]);
int nd=2; // next_d
while(nd<n){
while(ch.size()>=2){
pii d2=ch.back();
ch.pop_back();
pii d1=ch.back();
if(ccw(d1,d2,d[nd])>0){
ch.push_back(d2);
break;
}
}
ch.push_back(d[nd++]);
}
printf("%d",ch.size());
}
10. 인접행렬 거듭제곱
#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
typedef long long ll;
const ll mod=1e9+7;
int n,k;
ll ANS[100][100];
ll A[100][100];
void mult()
{
ll T[100][100]={};
rep(i,n) rep(j,n) rep(k,n) T[i][j]=(T[i][j]+ANS[i][k]*A[k][j])%mod;
rep(i,n) rep(j,n) ANS[i][j]=T[i][j];
}
void matpow()
{
ll T[100][100]={};
int i,j,k;
rep(i,n) rep(j,n) rep(k,n) T[i][j]=(T[i][j]+A[i][k]*A[k][j])%mod;
rep(i,n) rep(j,n) A[i][j]=T[i][j];
}
int main()
{
scanf("%d%d",&n,&k);
rep(i,n) ANS[i][i]=1;
rep(i,n) rep(j,n) scanf("%lld",&A[i][j]);
while(k){
if(k&1) mult();
matpow();
k>>=1;
}
ll ans=0;
rep(i,n) rep(j,n) ans=(ans+ANS[i][j])%mod;
printf("%lld",ans);
}
11. 루카스 정리 (1도 쓸모 없다)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int fac[2000],inv[2000]; // mod_max
int mod;
int fpow(int x,int y)
{
int res=1;
while(y){
if(y&1) res=1LL*res*x%mod;
x=1LL*x*x%mod;
y>>=1;
}
return res;
}
int lucas(ll n,ll k)
{
int res=1;
while(k){
int n1=n%mod,k1=k%mod;
if(n1<k1) return 0;
res=1LL*res*fac[n1]%mod*inv[k1]%mod*inv[n1-k1]%mod;
n/=mod,k/=mod;
}
return res;
}
int main()
{
ll n,k;
scanf("%lld%lld%d",&n,&k,&mod);
fac[0]=inv[0]=1;
for(int i=1;i<mod;i++) fac[i]=fac[i-1]*i%mod;
inv[mod-1]=fpow(fac[mod-1],mod-2);
for(int i=mod-2;i>0;i--) inv[i]=inv[i+1]*(i+1)%mod;
printf("%d",lucas(n,k));
}
12. Sparse Table
#include<bits/stdc++.h>
using namespace std;
int f[200001][19];
int main()
{
int m,q;
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&f[i][0]);
for(int j=1;j<19;j++) for(int i=1;i<=m;i++) f[i][j]=f[f[i][j-1]][j-1];
scanf("%d",&q);
while(q--){
int n,x;
scanf("%d%d",&n,&x);
for(int i=0;i<19;i++) if(n&(1<<i)) x=f[x][i];
printf("%d\n",x);
}
}
13. LCA
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
vector<int> ad[N];
int dep[N],par[N][17];
void make_tree(int cur,int prv) {
for(auto nxt : ad[cur]){
if(nxt==prv) continue;
dep[nxt]=dep[cur]+1, par[nxt][0]=cur;
make_tree(nxt,cur);
}
}
int lca(int u,int v) {
if(dep[u]<dep[v]) swap(u,v);
int diff=dep[u]-dep[v];
for(int i=0;i<17;i++) if(diff&(1<<i)) u=par[u][i];
if(u==v) return u;
for(int i=16;i>=0;i--)
if(par[u][i]!=par[v][i]) u=par[u][i], v=par[v][i];
return par[u][0];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n; cin >> n;
for(int i=1;i<n;i++){
int u,v; cin >> u >> v;
ad[u].push_back(v);
ad[v].push_back(u);
}
make_tree(1,0);
for(int j=1;j<17;j++) for(int i=1;i<=n;i++)
par[i][j]=par[par[i][j-1]][j-1];
int q; cin >> q;
while(q--){
int u,v; cin >> u >> v;
cout << lca(u,v) << '\n';
}
}
14. 위상 정렬
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
vector<int> id(n+1);
vector<int> ad[32001];
while(m--){
int a,b;
scanf("%d%d",&a,&b);
id[b]++;
ad[a].push_back(b);
}
queue<int> q;
for(int i=1;i<=n;i++) if(!id[i]) q.push(i);
for(int i=0;i<n;i++){
if(q.empty()){
printf("-1");
return 0;
}
int idx=q.front();
printf("%d ",idx);
q.pop();
for(int nidx: ad[idx])
if(--id[nidx]==0) q.push(nidx);
}
}
15. 벨만-포드, SPFA, 플로이드 와샬 (추가 예정) (귀찮음)
16. 최소 스패닝 트리 (크루스칼 알고리즘)
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
typedef pair<int,pair<int,int>> piii;
vector<int> p;
int fnd(int x)
{
if(p[x]==x) return x;
return p[x]=fnd(p[x]);
}
bool uni(int a,int b)
{
a=fnd(a),b=fnd(b);
if(a==b) return false;
p[max(a,b)]=min(a,b);
return true;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
p.resize(n+1);
for(int i=1;i<=n;i++) p[i]=i;
vector<piii> e(m);
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[i].X=c, e[i].Y={a,b};
}
sort(e.begin(),e.end());
int ans=0,cnt=0;
for(int i=0;;i++){
if(uni(e[i].Y.X,e[i].Y.Y)){
ans+=e[i].X;
if(++cnt==n-1) break;
}
}
printf("%d",ans);
}
17. 행렬 거듭제곱 DP 일반화