模板集合
hello~ 这里是nihachu(叫niki就好)!
这里是各种算法的模板集合,主要是方便自己背板子用的,后续会不定期更新,希望能帮到和我一样的小伙伴,也希望各路大神可以帮忙指正或补充,thanks~
(部分代码来自网络,若有侵权,请联系我删除,感谢!)
动态规划:
01背包(已降维)
for(int i = 1; i <= n; i ++){
for(int j = m; i >= w[i]; j --){
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
}
}
完全背包
for(int i = 1; i <= n ; i ++){
for(int j = w[i]; i <= m; j ++){
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
}
}
背包计数
for(int i = 1; i <= n; i ++){
for(int j = m; i >= w[i]; j --){
dp[j] += dp[j - w[i]];
}
}
(若要求恰好为m,则dp[0]初始化为1,其他均为0);
二进制拆分(用于多重背包)
for(int i = 1; i <= n1; i ++){
scanf("%d %d %d",&a, &b, &c);
for(int k = 1; k <= c; k <<= 1){
v[++u] = k * a; w[u] = k * b;
c -= k;
}
if(c) v[++u] = a * c,w[u] = b * c;
}
树上背包
//siz为体积,val为点权
void dfs(int x){
for(int i = siz[x]; i <= m; i ++) dp[x][i] = val[x];
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
dfs(v);
for(int u = m - siz[x]; u >= 0; u --){
for(int k = 0; k <= u; k ++){
dp[x][u + siz[x]] = max(dp[x][u + siz[x]],dp[x][u + siz[x] - k] + dp[v][k]);
}
}
}
}
或者
memset(dp,-0x3f,sizeof(dp));
void dfs(int x){
for(int i = 1; i <= m; i ++) dp[x][i] = v[x];
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
dfs(v);
for(int u = m; u >= 1; u --){
for(int k = 0; k <= u; k ++){
dp[x][u] = max(dp[x][u],dp[x][u - k] + dp[v][k]);
}
}
}
}
时间优化
快读
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',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');
return;
}
手动o2优化
-std=c++11 -O2
超级快读
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
char buf[MAXSIZE], *p1, *p2;
char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
IO() : p1(buf), p2(buf), pp(pbuf) {}
~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
#endif
char gc() {
#if DEBUG // 调试,可显示字符
return getchar();
#endif
if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
return p1 == p2 ? ' ' : *p1++;
}
bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template <class T>
void read(T &x) {
double tmp = 1;
bool sign = 0;
x = 0;
char ch = gc();
for (; !isdigit(ch); ch = gc())
if (ch == '-') sign = 1;
for (; isdigit(ch); ch = gc()) x = x * 10 + (ch - '0');
if (ch == '.')
for (ch = gc(); isdigit(ch); ch = gc())
tmp /= 10.0, x += tmp * (ch - '0');
if (sign) x = -x;
}
void read(char *s) {
char ch = gc();
for (; blank(ch); ch = gc());
for (; !blank(ch); ch = gc()) *s++ = ch;
*s = 0;
}
void read(char &c) { for (c = gc(); blank(c); c = gc()); }
void push(const char &c) {
#if DEBUG // 调试,可显示字符
putchar(c);
#else
if (pp - pbuf == MAXSIZE) fwrite(pbuf, 1, MAXSIZE, stdout), pp = pbuf;
*pp++ = c;
#endif
}
template <class T>
void write(T x) {
if (x < 0) x = -x, push('-'); // 负数输出
static T sta[35];
T top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) push(sta[--top] + '0');
}
template <class T>
void write(T x, char lastChar) {
write(x), push(lastChar);
}
} io;
io.read(n);
io.write(n,'\n');
图论
链式前向星
void add(int x, int y){
to[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
}
图的遍历
dfs:
void dfs(int x){
vis[x] = 1;
printf("%d\n",x);
for(int i = head[x];i;i = nxt[i])
if(!vis[to[i]]) dfs(to[i]);
}
bfs :
void bfs(int x){
z[++top] = x;
for(int i = 1; i <= top; i ++){
int now = z[top ++];
printf("%d\n",now);
for(int j = head[now]; j; j = nxt[j]){
if(!vis[to[j]])
vis[to[j]] = 1, z[++top] = to[j];
}
}
欧拉路径/回路
1)判断是不是欧拉路径/回路
for(int i = 64; i <= 125; i ++){
if(du[i] % 2) jud ++ ; //记录入度为奇数的点
}
if(!jud) //是欧拉回路
if(jud == 2) //是欧拉路径
if(jud && jud != 2)//啥也不是
}
2)欧拉路径/回路的遍历
void dfs(int x){
for(int i = head[x]; i; i = nxt[i])
if(!vis[i]) vis[i] = 1, dfs(to[i]);
printf("%d",x);
}
3)遍历环并记录长度
void dfs(int x,int dt){
if(vis[x]){
ans = min(ans,dt - d[x]);
}
else{
vis[x] = true;
d[x] = dt;
dfs(to[x],dt + 1);
}
}
拓扑排序
for(int i = 1; i <= n ; i ++) if(du[i] == 0) z[++top];
for(int i = 1; i <= top; i ++){
for(int j = head[z[i]]; j; j = nxt[j]){
du[to[j]] --;
if(du[to[j]] == 0) z[++top] = to[j];
}
}
dj
void dj(int u){
memset(dis,0x3f,sizeof(dis));
q.push({u,0});
dis[u] = 0;
while(!q.empty()){
int x = q.top().x;
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(dis[v] > dis[x] + 1){
dis[v] = dis[x] + 1;
q.push({v,dis[v]});
}
}
}
}
spfa(判负环)
bool spfa(int s){
queue<int> q;
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;
q.push(s);
while(!q.empty()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = head[x]; i; i = nxt[i]){
int t = to[i];
if(dis[t] > dis[x] + v[i]){
dis[t] = dis[x] + v[i];
if(!vis[t]){
vis[t] = 1;
q.push(t);
gt[t] ++;
}
if(gt[t] > n) return true;
}
}
}
return false;
}
kruskal
void kruskal(){
sort(e + 1, e + m + 1, cmp);
for(int i = 1; i <= n; i ++) fa[i] = i;
for(int i = 1; i <= m; i ++){
int r1 = find(e[i].x);
int r2 = find(e[i].y);
if(r1 == r2) continue;
fa[r1] = r2;
ans += e[i].z;
tot = max(tot,e[i].z);
cnt ++;
if(cnt == n - 1) break;
}
}
倍增求LCA
void dfs(int s, int fath){
f[s][0] = fath;
dep[s] = dep[fath] + 1;
for(int u = 1; u <= 20; u ++){
f[s][u] = f[f[s][u - 1]][u - 1];
}
for(int i = head[s]; i; i = nxt[i]){
int t = to[i];
if(t == fath) continue;
dis[t] = dis[s] + v[i];
dfs(t,s);
}
}
int lca(int x, int y){
if(dep[x] < dep[y]){
swap(x,y);
}
for(int i = 20; i >= 0; i --){
if(dep[f[x][i]] >= dep[y]) x = f[x][i];
}
if(x == y) return x;
for(int i = 20; i >= 0; i --){
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
}
return f[x][0];
}
void ask(int x, int y, int lca){
printf("%d\n",dis[x] + dis[y] - 2 * dis[lca]);
return;
}
tarjan
void tarjan(int u){
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i = head[u]; i; i = nxt[i]){
int v = to[i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!sccnum[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
scccnt ++;
while(1){
int x = s.top();
s.pop();
sccnum[x] = scccnt;
sccsu[scccnt] += w[x];
// sccsz[scccnt] ++;
if(x == u) break;
}
}
}
tarjan + 拓扑排序 + dp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int dfn[N],low[N],sccnum[N],sccsu[N],sccsz[N],scccnt,dfs_clock;
int head[N],nxt[N],to[N],cnt;
int afhe[N],afnx[N],afto[N],afcnt;
stack <int> s;
int n, m, du[N], val[N], v[N], w[N], ans;
queue<int> q;
void add(int x, int y){
to[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
}
void afad(int x, int y){
afto[++afcnt] = y;
afnx[afcnt] = afhe[x];
afhe[x] = afcnt;
}
void tarjan(int u){
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i = head[u]; i; i = nxt[i]){
int v = to[i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!sccnum[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
scccnt ++;
while(1){
int x = s.top();
s.pop();
sccnum[x] = scccnt;
sccsu[scccnt] += w[x];
// sccsz[scccnt] ++;
if(x == u) break;
}
}
}
void afbuild(){
for(int i = 1; i <= n; i ++){
for(int u = head[i]; u; u = nxt[u]){
int v1 = to[u];
if(sccnum[i] != sccnum[v1]){
afad(sccnum[i],sccnum[v1]);
// printf("%d %d %d %d e\n",i,v1,sccnum[i],sccnum[v1]);
++du[sccnum[v1]];
}
}
}
}
void topo(){
for(int i = 1; i <= scccnt; i ++) if(du[i] == 0) q.push(i), val[i] += sccsu[i];
while(!q.empty()){
int x = q.front();
q.pop();
// printf("x = %d, val = %d\n",x,val[x]);
for(int i = afhe[x]; i; i = afnx[i]){
int v1 = afto[i];
du[v1] --;
// printf("%d %d\n",val[v1],val[x] + sccsu[v1]);
val[v1] = max(val[v1],val[x] + sccsu[v1]);
// printf("v1 = %d, val = %d\n",v1,val[v1]);
if(du[v1] == 0){
q.push(v1);
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n ; i ++)
scanf("%d",&w[i]);
// return 0;
for(int i = 1, u, v; i <= m ; i ++){
scanf("%d%d",&u,&v);
add(u,v);
}
// return 0;
for(int i = 1; i <= n ; i ++){
if(!dfn[i]) tarjan(i);
}
// for(int i = 1; i <= n ; i ++){
// printf("i = %d, sccnum = %d\n",i,sccnum[i]);
// }
// for(int i = 1; i <= scccnt; i ++){
// printf("num = %d, sum = %d\n",i,sccsu[i]);
// }
afbuild();
topo();
for(int i = 1; i <= scccnt; i ++) ans = max(ans,val[i]);
printf("%d\n",ans);
return 0;
}
求割点
void tarjan(int u, int anc){
dfn[u] = low[u] = ++dfn_clock;
s.push(u);
int child = 0;
for(int i = head[u]; i; i = nxt[i]){
int v = to[i];
if(!dfn[v]){
tarjan(v,anc);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u] && u != anc) cut[u] = 1;
if(u == anc) child ++;
}
else if(!sccnum[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(dfn[u] == low[u]){
++scccnt;
while(1){
int x = s.top();
s.pop();
sccnum[x] = scccnt;
if(x == u) break;
}
}
// printf("%d %d %d %d %d\n",u,anc,dfn[u],low[u],child);
if(child >= 2 && u == anc) cut[u] = 1;
}
树剖
struct node{
long long sum,tag;
};
node tr[4 * N];
void pushup(int p){
tr[p].sum = tr[p * 2].sum + tr[p * 2 + 1].sum;
tr[p].sum %= mod;
}
void pushdown(int p, int s, int t){
int mid = (s + t) / 2;
tr[p * 2].sum += (mid - s + 1) * tr[p].tag;
tr[p * 2 + 1].sum += (t - mid) * tr[p].tag;
tr[p * 2].sum %= mod;
tr[p * 2 + 1].sum %= mod;
tr[p * 2].tag += tr[p].tag;
tr[p * 2 + 1].tag += tr[p].tag;
tr[p * 2].tag %= mod;
tr[p * 2 + 1].tag %= mod;
tr[p].tag = 0;
}
void build(int l,int r, int p){
if(l == r){
tr[p].sum = segw[l];
tr[p].sum %= mod;
return;
}
int mid = (l + r) / 2;
build(l,mid,p * 2);
build(mid + 1,r,p * 2 + 1);
pushup(p);
return;
}
void segupd(int p, int s, int t, int l, int r,int x){
if(t < l || s > r) return;
if(l <= s && t <= r){
tr[p].sum += (t - s + 1) * x;
tr[p].tag += x;
return;
}
int mid = (s + t) / 2;
pushdown(p,s,t);
segupd(p * 2, s, mid, l, r, x);
segupd(p * 2 + 1, mid + 1, t, l, r, x);
pushup(p);
return;
}
int segq(int p, int s, int t, int l, int r){
if(t < l || s > r) return 0;
if(l <= s && t <= r){
return tr[p].sum;
}
int mid = (s + t) / 2;
pushdown(p,s,t);
int ans = 0;
ans += segq(p * 2, s, mid, l, r);
ans += segq(p * 2 + 1, mid + 1, t, l, r);
pushup(p);
ans %= mod;
return ans;
}
void dfs1(int x, int f){
siz[x] = 1;
fa[x] = f;
dep[x] = dep[f] + 1;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(v == f) continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]]){
son[x]=v;
}
}
}
void dfs2(int x,int topf){
top[x] = topf;
dfn[x] = ++cnt;
rev[cnt] = x;
segw[cnt] = w[x];
if(son[x]){
dfs2(son[x],topf);
}
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(v == fa[x] || v == son[x]) continue;
dfs2(v,v);
}
}
void updrange(int x, int y, int z){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
segupd(1,1,n,dfn[top[x]],dfn[x],z);
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x,y);
segupd(1,1,n,dfn[y],dfn[x],z);
}
int qrange(int x, int y){
long long ans = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans += segq(1,1,n,dfn[top[x]],dfn[x]);
ans %= mod;
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x,y);
ans += segq(1,1,n,dfn[y],dfn[x]);
ans %= mod;
return ans;
}
void updtr(int x, int z){
segupd(1,1,n,dfn[x],dfn[x] + siz[x] - 1,z);
}
int qtr(int x){
return segq(1,1,n,dfn[x],dfn[x] + siz[x] - 1);
}
dinic
struct DINIC{
int cur[N],dep[N];
bool vis[N];
queue<int> q;
bool bfs(){
for(int i = 0; i <= t; i ++){
dep[i] = inf, cur[i] = head[i], vis[i] = 0;
}
q.push(s);
dep[s] = 0;
while(!q.empty()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(dep[v] > dep[x] + 1 && w[i]){
dep[v] = dep[x] + 1;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
if(dep[t] != inf) return 1;
else return 0;
}
ll dfs(int x, ll flow){
ll rlow = 0;
if(x == t){
maxflow += flow;
return flow;
}
ll used = 0;
for(int i = cur[x]; i; i = nxt[i])
{
int v = to[i];
cur[x] = i;
if(dep[v] == dep[x] + 1 && w[i]){
if(rlow = dfs(v,min(flow - used,w[i]))){
used += rlow;
w[i] -= rlow;
w[i^1] += rlow;
if(used == flow) break;
}
}
}
return used;
}
ll dinic(){
while(bfs()){
dfs(s,inf);
}
return maxflow;
}
}di;
isap
void bfs(){
for(int i = 0; i <= n + 1; i++){
dep[i] = -1;
gap[i] = 0;
cur[i] = head[i];
}
q.push(t);
dep[t] = 0;
gap[0] = 1;
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(dep[v] != -1) continue;
dep[v] = dep[x] + 1;
gap[dep[v]] ++;
q.push(v);
}
}
}
ll dfs(int x,int flow){
if(x == t){
maxflow += flow;
return flow;
}
ll used = 0;
for(int i = cur[x]; i; i = nxt[i]){
cur[x] = i;
int v = to[i];
if(dep[v] + 1 == dep[x] && w[i]){
int rlow = dfs(v,min(flow - used, w[i]));
if(rlow){
w[i] -= rlow;
w[i ^ 1] += rlow;
used += rlow;
}
if(rlow == used) return used;
}
}
gap[dep[x]] --;
if(gap[dep[x]] == 0) dep[s] = n + 1;
dep[x]++;
gap[dep[x]] ++;
return used;
}
ll isap(){
maxflow = 0;
bfs();
while(dep[s] < n){
memcpy(cur,head,sizeof(head));
dfs(s,0x3ffffff);
}
return maxflow;
}
dinic费用流
bool spfa(){
for(int i = 1; i <= n; i ++){
vis[i] = 0, dep[i] = 0x3fffff; cur[i] = head[i];
}
q.push(s);
dep[s] = 0;
while(!q.empty()){
int x = q.front();
q.pop();
// printf("x = %d\n",x);
vis[x] = 0;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
// printf(" v = %d\n",v);
if(dep[v] > dep[x] + c[i] && w[i]){
dep[v] = dep[x] + c[i];
// printf(" depv = %d\n",dep[v]);
if(!vis[v]){
// printf("v.inque\n");
vis[v] = 1;
q.push(v);
}
}
}
}
if(dep[t] != 0x3fffff) return 1;
else return 0;
}
ll dfs(int x,ll flow){
if(x == t){
vis[t] = 1;
maxflow += flow;
return flow;
}
ll used = 0;
ll rlow = 0;
vis[x] = 1;
for(int i = head[x]; i; i = nxt[i]){
// cur[x] = i;
int v = to[i];
if(dep[v] == dep[x] + c[i] && w[i] && (!vis[v] || v == t ) ){
rlow = dfs(v, min(flow - used, w[i]));
if(rlow != 0){
cost += rlow * c[i];
used += rlow;
w[i] -= rlow;
w[i ^ 1] += rlow;
}
if(used == flow){
break;
}
}
}
return used;
}
ll dinic(){
while(spfa()){
vis[t] = 1;
while(vis[t]){
memset(vis,0,sizeof(vis));
dfs(s,0x3fffffff);
}
}
return maxflow;
}
如果两点之间边比较多,以防被卡可以用这个
struct DINIC{
int dis[N], cur[N], dep[N];
bool vis[N];
bool spfa(){
deque<int> q;
for(int i = 0; i <= t; i ++) dis[i] = inf, cur[i] = head[i], vis[i] = 0, dep[i] = 0;
q.push_front(s), dis[s] = 0;
int len = 1, sum = 0;
while(!q.empty()){
int x = q.front(); q.pop_front();
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(dis[v] > dis[x] + c[i] && w[i]){
dis[v] = dis[x] + c[i];
dep[v] = dep[x] + 1;
if(!vis[v]){
if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
else q.push_back(v);
vis[v] = 1;
len ++; sum += dis[v];
}
}
}
vis[x] = 0;
}
return dis[t] != inf;
}
int dfs(int x, int flow){
if(x == t){ maxflow += flow; return flow; }
int rlow = 0, used = 0;
vis[x] = 1;
for(int i = cur[x]; i; i = nxt[i]){
cur[x] = i;
int v = to[i];
if(dep[v] == dep[x] + 1 && dis[v] == dis[x] + c[i] && w[i] && (!vis[v]|| v == t) ){
rlow = dfs(v, min(flow - used, w[i]));
if(rlow){
cost += rlow * c[i];
w[i] -= rlow;
w[i ^ 1] += rlow;
used += rlow;
if(used == flow) break;
}
}
}
return used;
}
int dinic(){
while(spfa()){
dfs(s, inf);
}
return maxflow;
}
}di;
2sat
void tarjan(int x){
dfn[x] = low[x] = ++dfn_clock;
s.push(x);
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(!dfn[v]){
tarjan(v);
low[x] = min(low[x], low[v]);
}
else if(!sccnum[v]){
low[x] = min(low[x], dfn[v]);
}
}
if(low[x] == dfn[x]){
++scccnt;
while(1){
int u = s.top();
s.pop();
sccnum[u] = scccnt;
if(x == u) break;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1, x, a, y, b; i <= m ; i ++){
scanf("%d%d%d%d",&x,&a,&y,&b);
// printf("%d %d, %d %d\n", x + (n*(1-a)), y + (n*b), y + (n*(1-b)), x + (n*a));
add(x + (n*(1-a)),y + (n*b) );
add(y + (n*(1-b)),x + (n*a) );
}
for(int i =1; i <= 2*n; i ++) if(!dfn[i]) tarjan(i);
for(int i = 1; i <= n ; i ++){
if(sccnum[i] == sccnum[i + n] && sccnum[i] != 0){
printf("IMPOSSIBLE");
return 0;
}
else{
if(sccnum[i] < sccnum[i + n]) ans[i] = 0;
else ans[i] = 1;
}
}
printf("POSSIBLE\n");
for(int i = 1; i <= n ; i ++){
printf("%d ",ans[i]);
}
return 0;
}
二分图最大匹配(dinic)
bool bfs(){
for(int i = 0; i <= n + m + 1; i ++){
dep[i] = 0x3ffffff, vis[i] = 0, cur[i] = head[i];
}
q.push(s);
dep[s] = 0;
while(!q.empty()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(dep[v] > dep[x] + 1 && w[i]){
dep[v] = dep[x] + 1;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
if(dep[t] != 0x3ffffff) return 1;
else return 0;
}
ll dfs(int x, int flow){
if(x == t){
maxflow += flow;
return flow;
}
ll used = 0;
ll rlow = 0;
for(int i = cur[x]; i; i = nxt[i]){
cur[x] = i;
int v = to[i];
if(dep[v] == dep[x] + 1 && w[i]){
if(rlow = dfs(v,min(flow - used, w[i]))){
used += rlow;
w[i] -= rlow;
w[i ^ 1] += rlow;
if(used == flow) break;
}
}
}
return used;
}
ll dinic(){
while(bfs()){
dfs(s,0x3ffffff);
}
return maxflow;
}
匈牙利算法
bool fd(int u){
for(int i = head[u]; i ;i = nxt[i]){
int v = to[i];
if(!vis[v]){
vis[v] = 1;
if(!cy[v] || fd(cy[v])){
cy[v] = u;
return true;
}
}
}
return false;
}
for(int i = 1; i <= n ; i ++){
memset(vis,0,sizeof(vis));
if(fd(i)) ans ++;
}
点分治
void getrt(int x, int fa){
sz[x] = 1;
mx[x] = 0;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(vis[v] || v == fa) continue;
getrt(v,x);
sz[x] += sz[v];
mx[x] = max(mx[x],sz[v]);
}
mx[x] = max(mx[x], s - sz[x]);
if(mx[x] < mx[rt]){
rt = x;
}
}
void getdis(int u, int fa){
d[++tot] = dis[u];
for(int i = head[u]; i; i = nxt[i]){
int v = to[i];
if(vis[v] || v == fa) continue;
dis[v] = dis[u] + w[i];
getdis(v,u);
}
}
void calc(int x){
qwq = 0; t[0] = 1;
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(vis[v]) continue;
dis[v] = w[i], tot = 0, getdis(v,x);
for(int u = 1; u <= tot; u ++){
for(int k = 1; k <= m ; k ++){
if(q[k] >= d[u] && t[q[k] - d[u]]) ans[k] = 1;
}
}
for(int u = 1; u <= tot; u ++) if(d[u] <= 1e7) t[d[u]] = 1, tsh[++qwq] = d[u];
}
while(qwq) t[tsh[qwq--]] = 0;
}
void solve(int x){
vis[x] = 1, calc(x);
for(int i = head[x]; i; i = nxt[i]){
int v = to[i];
if(vis[v]) continue;
getrt(v,x);
s = sz[v], rt = 0, mx[0] = 1e9;
getrt(v,x);
solve(rt);
// printf("x = %d\n",x);
// tie();
}
}
数据结构
树状数组
int lowbit(int x){
return x & (-x);
}
void add(int x, int y){
for(int i = x; i <= n; i += lowbit(i)){
c1[i] += y;
c2[i] += y * x;
}
}
int query(int x){
int res = 0;
for(int i = x; i ; i -= lowbit(i)){
res += c1[i] * (x + 1) - c2[i];
}
return res;
}
ans = query(r) - query(l));
二维树状数组
int lowbit(int x){
return x & (-x);
}
void add(int x,int y, int z){
for(int i = x; i <= n ; i += lowbit(i)){
for(int u = y; u <= m; u += lowbit(u)){
c1[i][u] += z;
c2[i][u] += z * x;
c3[i][u] += z * y;
c4[i][u] += z * x * y;
}
}
}
int query(int x, int y){
int res = 0;
for(int i = x; i; i -= lowbit(i)){
for(int u = y;u; u -= lowbit(u)){
res += (x + 1)*(y + 1)*c1[i][u] - (y + 1)*c2[i][u] - (x + 1)*c3[i][u] + c4[i][u];
}
}
return res;
}
ans = query(a - 1,b - 1) + query(c,d) - query(a - 1,d) - query(c,b - 1);
单调队列
//n为数据个数,m为窗口长度;
for(int i = 1; i <= n; i ++){
if(q[head] <= i - m) head ++;
while(head <= tail && a[q[tail]] < a[i]) tail --;
q[++tail] = i;
ans[i] = a[q[head]];
}
for(int i = m ; i <= n ; i ++){
//对每个窗口中已选出的数据进行处理 ;
}
线段树
struct SEG{
#define mid ((s + t) >> 1)
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,s,mid
#define rson p<<1|1,mid+1,t
int sum[N<<2], tag[N<<2];
void pushup(int p){sum[p] = sum[ls] + sum[rs];}
void pushdown(int p,int s,int t){
tag[ls] += tag[p];
tag[rs] += tag[p];
sum[ls] += tag[p] * (mid - s + 1);
sum[rs] += tag[p] * (t - mid);
tag[p] = 0;
}
void build(int p, int s, int t){
if(s == t){sum[p] = a[s]; return;}
build(lson); build(rson); pushup(p);
}
void upd(int p, int s, int t, int l, int r, int x){
if(t < l || s > r) return;
if(l <= s && t <= r){sum[p] += (t - s + 1) * x, tag[p] += x; return;}
pushdown(p,s,t);
upd(lson,l,r,x); upd(rson,l,r,x);
pushup(p);
}
int query(int p, int s, int t, int l, int r){
if(t < l || s > r) return 0;
if(l <= s && t <= r) return sum[p];
pushdown(p,s,t);
return query(lson,l,r) + query(rson,l,r);
}
}seg;
ST表
void pre() {
logn[1] = 0;
logn[2] = 1;
for (int i = 3; i <= N - 1; i++) { //注意这里一定是N - 1 绝对不能是N
logn[i] = logn[i / 2] + 1;
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &st[i][0]);
pre();
for (int u = 1; u <= 20; u++) {
for (int i = 1; i + (1 << u) - 1 <= n; i++) {
st[i][u] = max(st[i][u - 1], st[i + (1 << (u - 1))][u - 1]);
}
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &l, &r);
int k = logn[r - l + 1];
printf("%d\n", max(st[l][k], st[r - (1 << k) + 1][k]));
}
return 0;
}
二维st表
scanf("%d%d%d",&n,&m,&k1);
for(int i = 1; i <= n ; i ++){
for(int u = 1; u <= m; u ++){
scanf("%d",&st[i][0][u][0]);
}
}
logn[1] = 0;
logn[2] = 1;
for(int i = 3; i <= N - 1; i ++){
logn[i] = logn[i / 2] + 1;
}
for(int k = 0; k <= 20; k ++){
for(int h = 0; h <= 20; h ++){
if(!k && !h) continue;
for(int i = 1; i + (1 << k) - 1 <= n; i ++){
for(int u = 1; u + (1 << h) - 1 <= m; u ++){
if(k) st[i][k][u][h] = max(st[i][k - 1][u][h],st[i + (1 << (k - 1))][k - 1][u][h]);
else st[i][k][u][h] = max(st[i][k][u][h - 1],st[i][k][u + (1 << (h - 1))][h - 1]);
// st[i][k][u][h] = max({st[i][k - 1][u][h - 1],
// st[i + (1 << (k - 1))][k - 1][u][h - 1],
// st[i][k - 1][u + (1 << (h - 1))][h - 1],
// st[i + (1 << (k - 1))][k - 1][u + (1 << (h - 1))][h - 1]});
}
}
}
}
for(int i = 1,x1,y1,x2,y2; i <= k1; i ++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int k1 = logn[x2 - x1 + 1];
int k2 = logn[y2 - y1 + 1];
printf("%d\n",max({st[x1][k1][y1][k2],
st[x2 - (1 << k1) + 1][k1][y1][k2],
st[x1][k1][y2 - (1 << k2) + 1][k2],
st[x2 - (1 << k1) + 1][k1][y2 - (1 << k2) + 1][k2]}));
}
分块
scanf("%lld%lld",&n,&m);
for(int i = 1; i <= n ; i ++){
scanf("%lld",&a[i]);
sum1[i] = sum1[i - 1] + a[i];
}
k = sqrt(n);
for(int i = 1; i <= n / k + 1 ; i ++){
for(int u = 1; u <= k && u <= n; u ++){
pos[u + (i - 1) * k] = i;
if(!pl[i])pl[i] = u + i * k - k;
pr[i] = min(u + i * k - k,n);
}
sum[i] = sum1[pr[i]] - sum1[pl[i] - 1];
}
for(int u = 1; u <= m ; u ++){
scanf("%lld%lld%lld",&opt,&l,&r);
if(opt == 1){
scanf("%lld",&c);
if(pos[r] - pos[l] > 1){
int l1 = pos[l] + 1;
while(l1 < pos[r]) tag[l1] += c,l1 ++;
for(int i = l; i <= pr[pos[l]]; i ++) a[i] += c,sum[pos[i]] += c;//printf("%d %d\n",i,a[i]);
for(int i = r; i >= pl[pos[r]]; i --) a[i] += c,sum[pos[i]] += c;//printf("%d %d\n",i,a[i]);
}
else for(int i = l; i <= r; i ++) a[i] += c,sum[pos[i]] += c;
}
else{
ans = 0;
if(pos[r] - pos[l] > 1){
int l1 = pos[l] + 1;
while(l1 < pos[r]){
ans = ans + sum[l1] + tag[l1] * (pr[l1] - pl[l1] + 1), l1++;
}
for(int i = l; i <= pr[pos[l]]; i ++) ans += a[i] + tag[pos[i]];//printf("%d %d\n",i,ans);
for(int i = r; i >= pl[pos[r]]; i --) ans += a[i] + tag[pos[i]];//printf("%d %d\n",i,ans);
}
else for(int i = l; i <= r; i ++) ans += a[i] + tag[pos[i]] ;
printf("%lld\n",ans);
}
左偏树
int find(int x){
return f(x) == x ? x : f(x) = find(f(x));
}
int merge(int x,int y){
if(!x || !y) return x + y ;
if(v(x) < v(y)) swap(x,y);
dp[x] += dp[y];
sz[x] += sz[y];
rs(x) = merge(rs(x),y);
if(d(ls(x)) < d(rs(x))) swap(ls(x),rs(x));
d(x) = d(rs(x)) + 1;
f(x) = f(rs(x)) = f(ls(x)) = x;
return x;
}
int pop(int x){
return merge(ls(x),rs(x));
}
Splay
struct SPLAY{
int son[N][2], cnt[N] ,sz[N], fa[N] , val[N];
int rt = 0, tot = 0;
int newnode(int x, int f){
val[++tot] = x;
fa[tot] = f;
son[tot][0] = son[tot][1] = 0;
cnt[tot] = sz[tot] = 1;
return tot;
}
void maintain(int x){
sz[x] = cnt[x] + sz[son[x][0]] + sz[son[x][1]];
}
bool getf(int x){
return x == son[fa[x]][1];
}
void rotate(int x){
int f = fa[x]; int gf = fa[f];
bool i = getf(x), u = getf(f);
son[f][i] = son[x][i ^ 1];
fa[son[x][i ^ 1]] = f;
son[x][i ^ 1] = f;
fa[f] = x, fa[x] = gf;
if(gf) son[gf][u] = x;
maintain(x);
maintain(f);
//
}
void splay(int x){
for(int f = fa[x]; f = fa[x]; rotate(x)){
if(fa[f]){
if(getf(f) == getf(x)) rotate(f);
else rotate(x);
}
}
rt = x;
}
void insert(int x){
if(rt == 0){
rt = newnode(x,0);
// printf(" rt = %d\n",rt);
return;
}
int now = rt, f = 0;
while(1){
if(val[now] == x){
cnt[now] ++;
maintain(now);
maintain(f);
splay(now);
return;
}
f = now;
now = son[f][x > val[f]];
if(!now){
now = newnode(x,f);
son[f][x > val[f]] = now;
// printf(" 1 : f = %d, valf = %d, now = %d, son = %d\n",f,val[f], now,getf(now));
maintain(f);
splay(now);
// printf(" 2 : rt = %d, val = %d, lson = %d, rson = %d\n",rt,val[rt],son[rt][0], son[rt][1]);
return;
}
}
}
int kth(int x){
int now = rt;
while(1){
if(sz[son[now][0]] >= x) now = son[now][0];
else if(sz[son[now][0]] + cnt[now] >= x) return val[now];
else{
x -= (sz[son[now][0]] + cnt[now]);
now = son[now][1];
}
}
}
int rank(int x){
int now = rt, ans = 0;
while(1){
if(!now) return ans + 1;
if(val[now] > x) now = son[now][0];
else if(val[now] == x){
ans += sz[son[now][0]];
splay(now);
return ans + 1;
}
else{
ans += cnt[now] + sz[son[now][0]];
now = son[now][1];
}
}
}
int findpre(){
int now = son[rt][0];
// printf("%d %d\n",rt,now);
while(son[now][1]) now = son[now][1];
return now;
}
int findnxt(){
int now = son[rt][1];
while(son[now][0]) now = son[now][0];
return now;
}
void del(int x){
int ss = rank(x);
// printf("rank = %d\n",rank(x));
if(cnt[rt] > 1) cnt[rt] --;
else{
if(!son[rt][1] && !son[rt][0]) rt = 0;
else if(!son[rt][0]) rt = son[rt][1], fa[rt] = 0;
else if(!son[rt][1]) rt = son[rt][0], fa[rt] = 0;
else{
int rs = son[rt][1];
int pre = findpre();
splay(pre);
son[pre][1] = rs;
fa[rs] = pre;
maintain(pre);
}
}
}
void tri(int x){
if(son[x][0]) tri(son[x][0]);
// printf(" %d %d\n",x,val[x]);
if(son[x][1]) tri(son[x][1]);
}
}splay;
FHQ
struct FHQTREAP{
int ls[N], rs[N], val[N], pri[N], sz[N];
int tot = 0, rt = 0;
void newnode(int x){
tot ++;
ls[tot] = rs[tot] = 0;
val[tot] = x, pri[tot] = rand();
sz[tot] = 1;
}
void upd(int x){
sz[x] = sz[ls[x]] + sz[rs[x]] + 1;
}
void split( int u,int x, int &l, int &r){
if(u == 0){
l = 0, r = 0;
return;
}
if(val[u] <= x){
l = u;
split(rs[u],x,rs[u],r);
}
else{
r = u;
split(ls[u],x,l,ls[u]);
}
upd(u);
return;
}
int merge(int l, int r){
if(!l || !r) return l + r;
if(pri[l] > pri[r]){
rs[l] = merge(rs[l],r);
upd(l);
return l;
}
else{
ls[r] = merge(l,ls[r]);
upd(r);
return r;
}
}
int insert(int x){
int l, r;
split(rt,x,l,r);
newnode(x);
rt = merge(merge(l,tot),r);
return tot;
}
void del(int x){
int l, r, m;
split(rt,x, l, r);
split(l,x - 1, l, m);
m = merge(ls[m], rs[m]);
rt = merge(merge(l,m),r);
}
int rank(int x){
int l, r;
split(rt,x - 1,l,r);
int res = sz[l] + 1;
rt = merge(l,r);
return res;
}
int kth(int u, int x){
// printf(" %d %d %d %d\n",u,ls[u],sz[ls[u]],x);
if(sz[ls[u]] + 1 == x) return u;
else if(sz[ls[u]] >= x) return kth(ls[u],x);
else return kth(rs[u], x - sz[ls[u]] - 1);
}
int pre(int x){
int l, r;
split(rt,x - 1, l, r);
int res = val[kth(l,sz[l])];
merge(l,r);
return res;
}
int nxt(int x){
int l, r;
split(rt,x,l,r);
int res = val[kth(r,1)];
merge(l,r);
return res;
}
}fhq;
数论
快速幂
注意:不开ll会炸
long long quickpow(long long a, long long b, long long n){
long long res = 1;
while(b){
if(b % 2 == 1) res = res * a % n;
a = a * a % n;
b /= 2;
}
return res % n;
}
矩阵快速幂
const int mod = 1e9 + 7;
const int lim = ;
long long n;
struct mat{
ll m[lim + 2][lim + 2];
};
mat f, ans, t, f1;
void matinit(mat &x){
for(int i = 1; i <= lim; i ++){
for(int u = 1; u <= lim; u ++){
if(i == u) x.m[i][u] = 1ll;
else x.m[i][u] = 0ll;
}
}
}
mat matmul(mat x, mat y){
mat z;
memset(z.m,0,sizeof(z.m));
for(int i = 1; i <= lim ; i ++){
for(int k = 1; k <= lim; k ++){
if(x.m[i][k]){
for(int u = 1; u <= lim; u ++){
z.m[i][u] += x.m[i][k] % mod * y.m[k][u] % mod;
z.m[i][u] %= mod;
}
}
}
}
return z;
}
mat matquickpow(mat a, long long b){
mat res;
matinit(res);
while(b){
if(b & 1) res = matmul(res,a);
a = matmul(a,a);
b >>= 1;
}
return res;
}
欧拉筛
void getprime(){
for(int i = 2; i <= n ; i ++){
if(pflag[i] == false) pri[++top] = i;
for(int q = 1; pri[q] * i <= n ; q ++){
pflag[pri[q] * i] = true;
if(i % pri[q] == 0) break;
}
}
}
算术基本定理
for(int i = 2; i * i <= A ; i ++){
if(A % i != 0) continue;
int num = 0;
while(A % i == 0){
A /= i;
num ++;
}
printf("%d %d\n",i,num);
work(i,B * num + 1);
}
if(A > 1) printf("%d %d",A,1);
exgcd
void exgcd(ll a, ll b, ll &x, ll &y){
if(!b){x = 1, y = 0; return;}
exgcd(b, a % b, y, x);
y -= x * (a / b);
}
lucas定理
ll C(ll n, ll m,ll mod){
if(m > n) return 0;
return jie[n] * qpow(jie[m],mod - 2, mod) % mod * qpow(jie[n - m],mod - 2, mod) % mod;
}
ll lucas(ll n, ll m,ll mod){
if(m == 0) return 1;
return C(n % mod, m % mod,mod) * lucas(n / mod, m / mod,mod) % mod;
}
中国剩余定理
ll crt(){
ll ans = 0;
for(int i = 1; i <= 4; i ++){
ll x, y; exgcd(mod / b[i],b[i],x,y);
x = (x + b[i]) % b[i];
a[i] = (a[i] + b[i]) % b[i];
ans = (ans + qmul(mod / b[i] * x, a[i])) % mod;
}
return ans % mod;
}
线性求逆元
inv[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (p - p / i) * inv[p % i];
inv[i] %= p;
}
求一个数的欧拉函数
int phi(int n){
int ans=n,num=1;
for(int i=2;i*i<=n;i++)
{
if(n%i)continue;
ans=ans/i*(i-1);
while(!(n%i))n/=i;
}
if(n^1) ans=ans/n*(n-1);
return ans;
}
线性筛欧拉函数
void init(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])p[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*p[j]<=n;j++){
vis[i*p[j]]=1;
if(!(i%p[j])){
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
}
线性筛莫比乌斯函数
void getmul(){
mu[1] = 1;
// int mn = min(m,n);
for(int i = 2; i <= N - 1 ; i ++){
if(!np[i]) pri[++tot] = i, mu[i] = -1;
for(int u = 1; u <= tot && pri[u] * i <= N - 1; u ++){
np[pri[u] * i] = 1;
mu[pri[u] * i] = -1 * mu[i];
if(i % pri[u] == 0){
mu[pri[u] * i] = 0;
break;
}
}
}
}
莫比乌斯反演
int ans = 0;
int r = 0;
for(int i = 1; i <= min(n, m); i = r + 1){
r = min(n / (n / i), m / (m / i));
ans += (s[r] - s[i - 1]) * (n / i) * (m / i);
}
字符串
哈希(习惯性采用双哈希)
for (int i = 1; i <= n; i++) {
cin >> s;
unsigned long long t1 = 0, t2 = 0;
for (int u = 0; u < s.size(); u++) {
t1 = s[u] * p1 + t1 * p1;
t2 = s[u] * p2 + t2 * p2;
}
hash1[i] = t1 + t2;
}
KMP
void kmp1(){
int j = 0;
for(int i = 2; i <= lb; i ++){
if(j&& b[i] != b[j + 1]) j = kmp[j];
if(b[i] == b[j + 1]) j ++;
kmp[i] = j;
}
j = 0;
for(int i = 1; i <= la; i ++){
while(j && a[i] != b[j + 1]) j = kmp[j];
if(a[i] == b[j + 1]) j ++;
if(j == lb){
cnt ++;
j = kmp[j];
}
}
}
trie树
void triein(string s) {
int l = s.size();
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!nex[p][c])
nex[p][c] = ++cnt;
p = nex[p][c];
// printf("1 %d %d %d\n",i,c,nex[p][c]);
}
++exist[p];
}
int triequery(string s) {
int l = s.size();
int p = 0;
int tot = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
p = nex[p][c];
//执行操作
}
return tot;
}
AC自动机
struct trie {
int fail, exist, nex[27];
bool vis;
};
trie tr[N];
void build(string s) {
int p = 0;
int l = s.size();
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!tr[p].nex[c])
tr[p].nex[c] = ++cnt;
p = tr[p].nex[c];
}
tr[p].exist++;
}
void getfail() {
queue<int> q;
for (int i = 0; i < 26; i++)
if (tr[0].nex[i])
q.push(tr[0].nex[i]);
// for(int i = 0; i < )
while (!q.empty()) {
int now = q.front();
q.pop();
// printf("now = %d\n",now);
for (int i = 0; i < 26; i++) {
if (!tr[now].nex[i])
tr[now].nex[i] = tr[tr[now].fail].nex[i];
else
tr[tr[now].nex[i]].fail = tr[tr[now].fail].nex[i], q.push(tr[now].nex[i]);
}
}
}
int AC(string s) {
int l = s.size();
int res = 0;
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
p = tr[p].nex[c];
for (int u = p; tr[u].exist != -1; u = tr[u].fail) {
res += tr[u].exist;
tr[u].exist = -1;
}
}
return res;
}
Manacher
char ms[N];
int l, mana[N], c = -1, r = -1, ans = -10;
int main(){
cin>>s;
for(int i = 1; i <= s.size(); i ++){
ms[i * 2 - 2] = '@';
ms[i * 2 - 1] = s[i - 1];
}
ms[s.size() * 2] = '@';
l = s.size()* 2;
for(int i = 0; i <= l; i ++){
if(i > r){
int pr = i;
while(ms[pr] == ms[i * 2 - pr] && i * 2 - pr >= 0){
mana[i] ++;
pr ++;
}
}
else{
int i1 = c * 2 - i;
int l1 = c * 2 - r;
if(i1 - mana[i1] + 1 > l1){
mana[i] = mana[i1];
}
else{
mana[i] = i1 - l1 + 1;
int r1 = r + 1;
while(ms[r1] == ms[i * 2 - r1] && i * 2 - r1 >= 0){
mana[i] ++;
r1 ++;
}
}
}
if(i + mana[i] - 1 > r) r = i + mana[i] - 1, c = i;
}
for(int i = 0; i <= l; i ++){
ans = max(ans, mana[i] - 1);
}
杂项
cdq分治
struct node {
int a, b, c, cnt, ans;
friend bool operator==(node e, node f) { return e.a == f.a && e.b == f.b && e.c == f.c; }
};
node e[N], tmp[N];
bool cmp(node e, node f) {
if (e.a != f.a)
return e.a < f.a;
else if (e.b != f.b)
return e.b < f.b;
else
return e.c < f.c;
}
bool cmp2(node e, node f) {
if (e.b != f.b)
return e.b < f.b;
else if (e.c != f.c)
return e.c < f.c;
else
return e.a < f.a;
}
struct BMP {
int c[M];
int lowbit(int x) { return x & (-x); }
void add(int x, int y) {
for (int i = x; i <= k; i += lowbit(i)) c[i] += y;
}
int query(int x) {
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += c[i];
return res;
}
} bmp;
void cdq(int l, int r) {
if (l == r)
return;
int mid = (l + r) / 2;
cdq(l, mid), cdq(mid + 1, r);
sort(e + l, e + mid + 1, cmp2);
sort(e + mid + 1, e + r + 1, cmp2);
int s = l, t = mid + 1;
while (t <= r) {
if (s > mid)
break;
while (s <= mid && e[s].b <= e[t].b) {
bmp.add(e[s].c, e[s].cnt);
s++;
}
e[t].ans += bmp.query(e[t].c);
t++;
}
// printf("%d %d %d %d %d\n",l,r,mid,s,t);
for (int i = t; i <= r; i++) e[i].ans += bmp.query(e[i].c);
// printf(" ans : "); for(int i = l; i <= r; i ++) printf("%d ",e[i].ans); printf("\n");
// printf(" e1 : "); for(int i = l; i <= r; i ++) printf("%d ",bmp.query(e[i].c)); printf("\n");
for (int i = l; i < s; i++) bmp.add(e[i].c, -1 * e[i].cnt);
// printf(" e2 : "); for(int i = l; i <= r; i ++) printf("%d ",bmp.query(e[i].c)); printf("\n");
return;
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &tmp[i].a, &tmp[i].b, &tmp[i].c);
}
int m = 0;
sort(tmp + 1, tmp + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
int tot = 1;
while (tmp[i] == tmp[i + 1]) {
i++, tot++;
}
e[++m] = tmp[i];
e[m].cnt = tot;
}
// printf("\n");
// for(int i = 1; i <= n ; i ++) printf("%d %d %d %d\n",e[i].a,e[i].b, e[i].c, e[i].cnt);
cdq(1, m);
for (int i = 1; i <= m; i++) {
res[e[i].ans + e[i].cnt - 1] += e[i].cnt;
}
for (int i = 0; i < n; i++) printf("%d\n", res[i]);
return 0;
}