我的板子3——图论



/*最小费用最大流
//给一个包含n个点和m条边的图,每条边(u,v)有一个流量限制w(u,v)和单位流量的费用c(u,v)
求出该网络的最小费用最大流,即在F(G)最大的前提下,是C(G)最小
// SPFA跑费用流 洛谷 P3381
#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
int read(){
    char c=getchar();
    int f = 1, ans = 0;
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        ans = ans*10 + c - '0';
        c = getchar();
    }
    return ans*f;
}
int s, t, cost[maxn], head[maxn], vis[maxn], flow[maxn], pre[maxn], last[maxn], cnt = -1;
struct node{
    int to, next, cost, flow;
}p[maxn*20];
queue<int> q;
void add(int x, int y, int f, int c){
    p[++cnt].next = head[x];
    head[x] = cnt;
    p[cnt].cost = c;
    p[cnt].flow = f;
    p[cnt].to = y;
}
bool spfa(){
    memset(vis, 0, sizeof(vis));
    memset(cost, 0x7f, sizeof(cost));
    flow[s] = 0x7ffffff;
    q.push(s), vis[s] = 1, cost[s] = 0, pre[t] = -1;
    while(!q.empty()){
        int now = q.front();
        q.pop();
        vis[now] = 0;
        for(int k = head[now]; k != -1; k = p[k].next){
            int x = p[k].to;
            if(p[k].flow > 0 && cost[x] > cost[now] + p[k].cost){
                cost[x] = cost[now] + p[k].cost;
                pre[x] = now;
                last[x] = k;
                flow[x] = min(flow[now], p[k].flow);
                if(!vis[x]){
                    vis[x] = 1;
                    q.push(x);
                }
            }
        }
    }
    return pre[t] != -1;
}
int maxflow, mincost;
void MCMF(){
    while(spfa()){
        int now = t;
        maxflow += flow[t];
        mincost += flow[t]*cost[t];
        while(now != s){
            p[last[now]].flow -= flow[t];
            p[last[now]^1].flow += flow[t];
            now = pre[now];
        }
    }
}

int main(){
    memset(head, -1, sizeof(head));
    int n, m, x, y, c, f;
    n = read(), m = read(), s = read(), t = read();
    for(int i = 1; i <= m; i++){
        x = read(), y = read(), f = read(), c = read();
        add(x, y, f, c);add(y, x, 0, -c);
    }
    MCMF();
    printf("%d %d\n",maxflow,mincost);
return 0;}

*/

/*网络最大流:给一个网络图,以及其源点和汇点,求出其网络最大流
//注意流量的定义
// 洛谷 P3376
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long LL;
const int maxn = 1e3 + 5;
const int inf = 1<<30;

int n, m, s, t, cnt;
int head[maxn], cur[maxn], dep[maxn];

queue<int> q;

struct node{
    int next, v;
    LL dis;
}edge[maxn << 5];

void add(int u, int v, LL dis){
    edge[cnt].v = v;
    edge[cnt].next = head[u];
    edge[cnt].dis = dis;
    head[u] = cnt++;
}

bool bfs(){
    memset(dep, 0x7f, sizeof(dep));
    for(int i = 1; i <= n; i++) cur[i] = head[i];
    dep[s] = 0;
    q.push(s);
    while(!q.empty()){
        int now = q.front();
        q.pop();
        for(int k = head[now]; ~k; k = edge[k].next){
            int v = edge[k].v;
            if(dep[v] > inf && edge[k].dis){
                dep[v] = dep[now] + 1;
                q.push(v);
            }
        }
    }
    return dep[t] < inf;
}

LL dfs(int now, int limit){
    if(!limit || now == t) return limit;
    LL flow = 0, ins;
    for(int k = cur[now]; ~k; k = edge[k].next){
        cur[now] = k;
        int v = edge[k].v;
        if(dep[v] == dep[now] + 1 && (ins = dfs(v, min(LL(limit), edge[k].dis)))){
            flow += ins;
            limit -= ins;
            edge[k].dis -= ins;
            edge[k^1].dis += ins;
            if(!limit) break;
        }
    }
    return flow;
}

LL Dinic(){
    LL maxflow = 0;
    while(bfs())
        maxflow += dfs(s, inf);
    return maxflow;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> m >> s >> t;
    memset(head, -1, sizeof(head));
    int u, v;
    LL c;
    for(int i = 1; i <= m; i++){
        cin >> u >> v >> c;
        add(u, v, c);
        add(v, u, 0);
    }
    cout << Dinic() << endl;
return 0;}

*/

/*二分图匹配匈牙利算法
//给定一个二分图,其左部点的个数为n,右部点的个数为m,边数为e,求最大匹配的边数
// 匈牙利算法 洛谷 P3386
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
struct node{
    int v, next;
}tree[maxn];

int cnt, head[1005], cx[1005], cy[1005];
bool vis[1005];

int dfs(int u){
    for(int k = head[u]; k; k = tree[k].next){
        int v = tree[k].v;
        if(!vis[v]){
            vis[v] = true;
            if(!cy[v] || dfs(cy[v])){
                cx[u] = v;
                cy[v] = u;
                return 1;
            }
        }
    }
    return 0;
}

int read(){
    char c = getchar();
    int f = 1, ans = 0;
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        ans = ans*10 + c - '0';
        c = getchar();
    }
    return ans*f;
}
int main(){
    int i, n, m, e, u, v, ans = 0;
    n = read(), m = read(), e = read();
    for(i = 1; i <= e; i++){
        u = read(), v = read();
        if(u > n || v > m) continue;
        tree[++cnt].v = v;
        tree[cnt].next = head[u];
        head[u] = cnt;
    }
    for(i = 1; i <= n; i++){
        if(head[i] && !cx[i]){
            memset(vis, 0, sizeof(vis));
            ans += dfs(i);
        }
    }
    printf("%d\n",ans);
return 0;}


*/


/*LCA最近公共祖先ST表
// ST表版本 洛谷 P3379
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
int dp[maxn][(int)log2(maxn) + 2], dep[maxn<<1], fa[maxn], first[maxn], cnt, ver[maxn], tol;
int head[maxn];
int read(){
    char c = getchar();
    int f = 1, ans = 0;
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        ans = ans*10 + c - '0';
        c = getchar();
    }
    return ans*f;
}

struct node{
    int next, v;
}tree[maxn<<1];

void dfs(int v, int f, int d){
    first[v] = ++cnt;
    fa[v] = f;
    dep[cnt] = d;
    ver[cnt] = v;
    for(int k = head[v]; ~k; k = tree[k].next){
        if(tree[k].v == f) continue;
        dfs(tree[k].v, v, d + 1);
        dep[++cnt] = d;
        ver[cnt] = v;
    }
}
void ST(){
    for(int i = 1; i <= cnt; i++)
        dp[i][0] = i;
    for(int j = 1; (1<<j) <= cnt; j++){
        int s = 1<<j;
        for(int i = 1; i + s - 1 <= cnt; i++){
            int a = dp[i][j - 1], b = dp[i + (1<<(j-1))][j - 1];
            dp[i][j] = dep[a] < dep[b] ? a : b;
        }
    }
}

int RMQ(int x, int y){
    x = first[x], y = first[y];
    if(x > y) swap(x, y);
    int k = (int)floor(log2(y - x + 1));
    int a = dp[x][k], b = dp[y - (1<<k) + 1][k];
    return ver[dep[a] < dep[b] ? a : b];
}

void add(int x, int y){
    tree[++tol].v = y;
    tree[tol].next = head[x];
    head[x] = tol;
}

int main(){
    int x, y, m, n, root, i;
    n = read(), m = read(), root = read();
    memset(head, -1, sizeof(head));
    for(i = 1; i < n; i++){
        x = read(), y = read();
        add(x, y);
        add(y, x);
    }
    dfs(root, 0, 1);
    ST();
    for(i = 1; i <= m; i++){
        x = read(), y = read();
        printf("%d\n", RMQ(x,y));
    }
return 0;}

*/

/*树上任意两点距离之和
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const ll mod=1e9+7;
int sum[maxn], n;
ll dp[maxn];
struct Edge
{
    int v, w;
};
vector<Edge> tree[maxn];
void dfs(int cur, int father)
{
    sum[cur] = 1;
    for(int i = 0; i < tree[cur].size(); i++)
    {
        int son = tree[cur][i].v;
        ll len = tree[cur][i].w;
        if(father == son)
            continue;
        dfs(son, cur);
        sum[cur] += sum[son];
        sum[cur]%=mod;
        dp[cur] =(dp[cur]+dp[son] + (((n-sum[son])*sum[son])%mod * len)%mod)%mod;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    calJc();
    while(cin>>n)
    {
        for(int i = 0; i <= n; i++)
            tree[i].clear();
        memset(sum, 0, sizeof(sum));
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n-1; i++)
        {
            ll u,v,w;
            cin>>u>>v>>w;
            Edge t1, t2;
            t1.v = v;
            t1.w = w;
            t2.v = u;
            t2.w = w;
            tree[u].push_back(t1);
            tree[v].push_back(t2);
        }
        dfs(1,0);
        cout<<dp[1]<<endl;
    }
    return 0;
}
*/

/*拓扑排序
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int MAX_N=10000;
struct edge
{
    int to,next;
}e[MAX_N];
int p[MAX_N],eid;
void init()
{
    eid=0;
    memset(p,-1,sizeof(p));
}
void insert(int u,int v)
{
    e[eid].to=v;
    e[eid].next=p[u];
    p[u]=eid++;
}
int indegree[MAX_N];
int n;
int topo()
{
    queue<int>Q;
    for(int i=1;i<=n;i++)
    {
        if(indegree[i]==0)
            Q.push(i);
    }
    while(!Q.empty())
    {
        int now=Q.front();
        cout<<"visting"<<now<<endl;
        Q.pop();
        for(int i=p[now];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            indegree[v]--;
            if(indegree[v]==0)
                Q.push(v);
        }
    }
}

//LeetCode课程表问题,给定课程总量以及他们的先决条件[0,1],返回你为了学完所有课程所安排的学习顺序
class Solution {
private:
    // 存储有向图
    vector<vector<int>> edges;
    // 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
    vector<int> visited;
    // 用数组来模拟栈,下标 0 为栈底,n-1 为栈顶
    vector<int> result;
    // 判断有向图中是否有环
    bool valid = true;

public:
    void dfs(int u) {
        // 将节点标记为「搜索中」
        visited[u] = 1;
        // 搜索其相邻节点
        // 只要发现有环,立刻停止搜索
        for (int v: edges[u]) {
            // 如果「未搜索」那么搜索相邻节点
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            }
            // 如果「搜索中」说明找到了环
            else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        // 将节点标记为「已完成」
        visited[u] = 2;
        // 将节点入栈
        result.push_back(u);
    }

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);
        }
        // 每次挑选一个「未搜索」的节点,开始进行深度优先搜索
        for (int i = 0; i < numCourses && valid; ++i) {
            if (!visited[i]) {
                dfs(i);
            }
        }
        if (!valid) {
            return {};
        }
        // 如果没有环,那么就有拓扑排序
        // 注意下标 0 为栈底,因此需要将数组反序输出
        reverse(result.begin(), result.end());
        return result;
    }
};


*/

/*线段树 区间加区间乘混合
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
typedef long long LL;
const int maxn = 1e5 + 5;
LL mod = 571373;
LL tree[maxn << 2], lazy[maxn << 2], mul[maxn << 2], a[maxn];

inline void push_up(int rt){
    tree[rt] = (tree[rt << 1] + tree[rt << 1 | 1]) % mod;
}

inline void build(int l, int r, int rt){
    if(l == r){
        tree[rt] = a[l];
        mul[rt] = 1;
    }
    else{
        int m = l + r >> 1;
        mul[rt] = 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
        push_up(rt);
    }
}

inline void push_down(int l, int r, int rt){
    int m = l + r >> 1, r1 = rt << 1, r2 = rt << 1 | 1;
    tree[r1] = (tree[r1] * mul[rt] + lazy[rt] * (m - l + 1)) % mod;
    tree[r2] = (tree[r2] * mul[rt] + lazy[rt] * (r - m)) % mod;
    lazy[r1] = (lazy[r1] * mul[rt] + lazy[rt]) % mod;
    lazy[r2] = (lazy[r2] * mul[rt] + lazy[rt]) % mod;
    lazy[rt] = 0;
    mul[r1] = mul[r1] * mul[rt] % mod;
    mul[r2] = mul[r2] * mul[rt] % mod;
    mul[rt] = 1;
}

inline void update1(int l, int r, int L, int R, LL c, int rt){
    if(L <= l && r <= R){
        tree[rt] = (tree[rt] + c * (r - l + 1)) % mod;
        lazy[rt] = (lazy[rt] + c) % mod;
        return;
    }
    push_down(l, r, rt);
    int m = l + r >> 1;
    if(L <= m) update1(l, m, L, R, c, rt << 1);
    if(R > m) update1(m + 1, r, L, R, c, rt << 1 | 1);
    push_up(rt);
    return;
}

inline void update2(int l, int r, int L, int R, int c, int rt){
    if(L <= l && r <= R){
        tree[rt] = tree[rt] * c % mod;
        mul[rt] = mul[rt] * c % mod;
        lazy[rt] = lazy[rt] * c % mod;
        return;
    }
    push_down(l, r, rt);
    int m = l + r >> 1;
    if(L <= m) update2(l, m, L, R, c, rt << 1);
    if(R > m) update2(m + 1, r, L, R, c, rt << 1 | 1);
    push_up(rt);
}

inline int query(int l, int r, int L, int R, int rt){
    if(L <= l && r <= R) return tree[rt];
    push_down(l, r, rt);
    int m = l + r >> 1, ans = 0;
    if(L <= m) ans = query(l, m, L, R, rt << 1);
    if(R > m) ans = (ans + query(m + 1, r, L, R, rt << 1 | 1)) % mod;
    return ans;
}

int main(){
    IOS;
    int n, m, l, r, c, flag;
    cin >> n >> m >> mod;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(1, n, 1);
    while(m--){
        cin >> flag;
        switch(flag){
            case 1 :
                cin >> l >> r >> c;
                update2(1, n, l, r, c, 1);
                break;
            case 2 :
                cin >> l >> r >> c;
                update1(1, n, l, r, c, 1);
                break;
            case 3 :
                cin >> l >> r;
                cout << query(1, n, l, r, 1) << endl;
        }
    }
}

*/

/*ST表
// 求区间最值 洛谷 P3865
// 给定一个长度为N的数列,和M次询问,求出每一次询问的区间内数字的最大值
#include<bits/stdc++.h>
using namespace std;
int n, k, num[100005];
int ma[100005][25];		// n*logn
void pre(){
    for(int i = 1; i <= n; i++)
        ma[i][0] = num[i];
    int s = 2, s2;
    for(int j = 1; s <= n; j++, s <<= 1){
            s2 = s;
        for(int i = 1; s2 <= n; i++, s2++)
            ma[i][j] = max(ma[i][j - 1], ma[i + (s>>1)][j - 1]);
    }
}
int qerry(int l, int r){
    int k = trunc(log2(r-l+1));	// floor
    return max(ma[l][k], ma[r - (1 << k) + 1][k]);
}
// 精髓就是这个区间查询,按区间长度找到对应层级
int main(){
    int q;
    cin >> n >> q;
    for(int i = 1; i <= n; i++)
        cin >> num[i];
    pre();
    int l, r;
    for(int i = 1; i <= q; i++){
        cin >> l >> r;
        cout << qerry(l,r)) << endl;
    }
	return 0;
}
// ST表还可以通过时间戳找LCA
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_AoSnow_

创作不易,打赏打赏些8

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值