目录
矩阵快速幂
最短路
最大流/最小割
二分图最大独立集
强连通分量
#include
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
struct Matrix{
ll m[2][2];
} ans,rec;
ll n,mod;
ll x0,x1,a,b;
Matrix Mul(Matrix a, Matrix b){
Matrix c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
c.m[i][j]=0;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
for(int k=0;k<2;k++)
c.m[i][j]+=a.m[i][k]*b.m[k][j];
c.m[i][j]=c.m[i][j]%mod;
}
return c;
}
Matrix pow(ll x){
Matrix ans;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
if(i==j)
ans.m[i][j]=1;
else
ans.m[i][j]=0;
}
while(x){
if(x%2)
ans=Mul(ans,rec);
rec=Mul(rec,rec);
x=x/2;
}
return ans;
}
int main(){
cin>>x0>>x1>>a>>b;
cin>>n>>mod;
rec.m[0][0]=a;rec.m[0][1]=b;
rec.m[1][0]=1;rec.m[1][1]=0;
Matrix tmp=pow(n-1);
cout<<(tmp.m[0][0]+tmp.m[0][1])%mod<
(dijstra+堆优化) O(ElogV) 无法处理负边情况
堆优化加前向星邻接表板子
struct Edge{
int v,w;//w为距离
int next;
};
Edge edge[maxn];
struct qnode{ //堆优化
int u;
int w;
qnode(int u=0,int w=0):u(u),w(w){}//构造函数
bool operator < (const qnode& a) const{//重载小于号
return w>a.w;
}
};
long long dis[maxn];
int head[maxn];
bool vis[maxn];
int size;
void add_edge(int u,int v,int w){//
edge[size].v=v;
edge[size].w=w;
edge[size].next=head[u];
head[u]=size;
size++;
}
void dijkstra(int s){
priority_queueq;
while(!q.empty())
q.pop();
q.push(qnode(s,0));
dis[s]=0;
while(!q.empty()){
qnode t=q.top();
q.pop();
int u=t.u;
if(vis[u])continue;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
int w=edge[i].w;
if(!vis[v]&&dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(qnode(v,dis[v]));
}
}
}
}
for(int i=1;i<=n;i++){//初始化
head[i]=-1;
dis[i]=inf;
vis[i]=false;
}
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
typedef long long ll;
const int N = 20005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
bool vis[N];
struct Edge{
int to;
ll cap, flow;
int next;//邻接点,容量,流量,next
}edge[N*50];
int n, m, cnt;//n是点 m是边 cnt是加边操作后的边
int head[N];//邻接表
int dis[N];//分层 等级
int cur[N];//弧优化
void add(int u, int v, ll w){
edge[cnt] = (struct Edge){v, w, 0, head[u]};
head[u] = cnt++;
edge[cnt] = (struct Edge){u, 0, 0, head[v]};
head[v] = cnt++;
}
bool bfs(int start, int endd){//分层
memset(dis, -1, sizeof(dis));
memset(vis, false, sizeof(vis));
queueque;
dis[start] = 0;
vis[start] = true;
que.push(start);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(!vis[E.to] && E.flow0){
edge[i].flow += f;
edge[i^1].flow -= f;
flow += f;
res -= f;
if(res == 0) break;
}
}
}
return flow;
}
ll max_flow(int start, int endd){
ll flow = 0;
while(bfs(start, endd)){
memcpy(cur, head, sizeof(head));//初始化弧优化数组
flow += dfs(start, INF, endd);
}
return flow;
}
void init(){//初始化
cnt = 0;
memset(head, -1, sizeof(head));
}
int main(){
scanf("%d%d", &n, &m);
init();
int sp=1;//源点
int tp=n;//汇点
for(int i = 1; i <= m; i++){
int x,y;
ll z;
scanf("%d%d%lld",&x,&y,&z);
add(x, y, z);
}
ll ans = max_flow(sp, tp);
printf("%lld\n", ans);
return 0;
}
#include
#define ll long long
using namespace std;
const int maxn = 5e3+5;//点
const int N = 3e7+5;//边
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int a[maxn];
int oddvis[maxn];//仅仅是为了区分左右集,该题是标记为左集,与此模板无关
bool vis[maxn];
struct Edge{
int to;
int cap, flow;
int next;
}edge[N];
int cnt;
int head[maxn];
int dis[maxn];
int cur[maxn];
void add(int u, int v, int w){
edge[cnt] = (struct Edge){v, w, 0, head[u]};
head[u] = cnt++;
edge[cnt] = (struct Edge){u, 0, 0, head[v]};
head[v] = cnt++;
}
bool bfs(int start, int endd){
memset(dis, -1, sizeof(dis));
memset(vis, false, sizeof(vis));
queueque;
dis[start] = 0;
vis[start] = true;
que.push(start);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(!vis[E.to] && E.flow0){
edge[i].flow += f;
edge[i^1].flow -= f;
flow += f;
res -= f;
if(res == 0) break;
}
}
}
return flow;
}
int max_flow(int start, int endd){
int flow = 0;
while(bfs(start, endd)){
memcpy(cur, head, sizeof(head));
flow += dfs(start, INF, endd);
}
return flow;
}
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
int main(){
std::ios::sync_with_stdio(false);
int n;
cin>>n;
int s=0;//建边
int e=n+1;
init();
////////////////建图 重写////////////
////////////////////////////////////
int num=max_flow(s,e);//二分图最大匹配
cout<
#include
#include
#include
#include
using namespace std;
int n,m,idx=0,cnt=1,Bcnt=0;
int head[100];
int vis[100];
int dfn[100],low[100];
int Belong[100];//belong表示每个点属于缩完之后的哪一个点
stack s;
struct edge{
int v,next;
}e[100];
void adde(int u,int v){
e[cnt].next=head[u];
e[cnt].v=v;
head[u]=cnt++;
}
void readdata(){
int a,b;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
adde(a,b);
}
}
void tarjan(int u){
int v;
dfn[u]=low[u]=++idx;//
s.push(u);//将u入栈
vis[u]=1;//标记u在栈内
for(int i=head[u];i!=-1;i=e[i].next){
v=e[i].v;
if(!dfn[v]){
tarjan(v);//dfs(v)
low[u]=min(low[u],low[v]);
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){//发现是整个强连通分量子树里的最小根。
Bcnt++;
do{ //具体处理强连通分量时改这里
v=s.top();
s.pop();
vis[v]=0;//表示出栈
Belong[v]=Bcnt;
}while(u != v);
}
}
void work(){
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);//保证每个点去找
printf("\n");
for(int i = 1;i <= 6;i++) printf("%d %d\n",dfn[i],low[i]);
printf("共有%d强连通分量,它们是:\n",Bcnt);
for(int i=1;i<=Bcnt;i++){
printf("第%d个:",i);
for(int j=1;j<=n;j++){
if(Belong[j]==i)
printf("%d ",j);
}
printf("\n");
}
}
int main(){
readdata();
work();
return 0;
}
/*
6 8
1 2
1 3
2 4
3 4
3 5
4 1
4 6
5 6
*/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
vector v;
struct node{
int l;
int r;
int sum;
}T[maxn*50];
int n,m,a[maxn],root[maxn],x,y,k,cnt;//cnt是第几棵树 root是存的第几棵树的根节点编号
int getid(int x){//得到离散化后的下标
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){//处理的下标 &能改变原有的数
T[++cnt]=T[y];//++cnt给新结点编号 主席树相当于前缀,所以记下上一个树节点的值 相当于pre[i]=pre[i-1]
T[cnt].sum++;//这一步相当于pre[i]=pre[i-1]+a[i]中的a[i] 因为主席树记的是数的个数 可持久化权值线段树
x=cnt; //y是x前面一棵树
if(l==r) return ;
int mid=(l+r)/2;
if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos);//若K小于等与mid,则两棵树共用右树
else update(mid+1,r,T[x].r,T[y].r,pos);//反之
}
int quert(int l,int r,int x,int y,int k){//返回的是离散后第K大下标
if(l==r) return l;
int mid=(l+r)/2;
int s=T[T[y].l].sum-T[T[x].l].sum;//是线段树左儿子的在区间[x,y]之内有多少个数;
if(k<=s) return quert(l,mid,T[x].l,T[y].l,k);//左子树足够找这K个数了
else return quert(mid+1,r,T[x].r,T[y].r,k-s);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());//离散化
v.erase(unique(v.begin(),v.end()),v.end());//去重
for(int i=1;i<=n;i++){
update(1,v.size(),root[i],root[i-1],getid(a[i]));
}
for(int i=0;i>x>>y>>k; //核心就是根据前缀和求差来计算
cout<
持续更新