快读快写
template<class T>inline void read(T &s){
int f=1; s=0;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f*=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
s*=f;
}
template<class T>inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
线段树
https://www.luogu.com.cn/blog/445476/post-shuo-ju-jie-gou-xian-duan-shu
树状数组
单点查询、区间修改:
int query(int x){
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum+=(x+1)*tree[i]-sum2[i];
return sum;
}
void change(int x,int v){
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=v,sum2[i]+=x*v;
}
trajan 求强连通分量
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
template<class T>inline void read(T &s){
int f=1; s=0;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f*=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
s*=f;
}
#define MAXN 100100
#define MAXM 1000100
#define ll long long
#define il inline
int st[MAXN],len;
//手写栈函数
il void clear(){
len=0;}
il int top(){
return st[len];}
il void push(int x){
st[++len]=x;}
il void pop(){
len--;}
int dfn[MAXN],low[MAXN],sum;
int n,m,cnt;
bool vis[MAXN];
vector<int> link[MAXN];
void dfs(int x){
push(x),vis[x]=1;
dfn[x]=low[x]=++sum;
for(int i=0;i<link[x].size();i++){
int y=link[x][i];
if(dfn[y]==0){
dfs(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]){
//y点还在栈里
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
cnt++;
while(1){
int now=top();
pop(),vis[now]=0;
if(now==x) break;
}
}
}
signed main(){
read(n),read(m);
while(m--){
int u,v;
read(u),read(v);
link[u].push_back(v);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);
printf("%d\n",cnt); //强连通分量的个数
return 0;
}
倍增 LCA
int dep[MAXN],f[MAXN][40];
void dfs(int x,int fa){
dep[x]=dep[fa]+1,f[x][0]=fa;
for(int i=1;(1<<i)<=dep[x];i++)
f[x][i]=f[f[x][<