2020/10/4

两题:

///链接:https://www.luogu.com.cn/problem/P2754
/*题意: n太空站,m飞船,每个飞船有以一固定且循环的航线,每一秒能移动一步,现在问你最起码要多少秒,才能把地球上的
        k个人转移到月球上去。
  题解:首先无解的情况,地球和月球之间没有路线,那么直接输出0;现在要考虑的是有解的情况。
  这里我们需要按照时间进行分层,即第一秒的时候图是怎么样的,跑下最大流,看最大流是否大于等于k。如果是,则直接退出;
  如果不是,则就证明当前时间还不满足,我们就看s+1秒的时候的最大流。直到满足最大流大于等于k。
  按时间建的分层图;有东西。
*/
#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("
");
#define Debug printf("this_ok
");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
",a);
typedef pair<int,int> PII;
inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}
const ll mod = 998244353;
const int N = 1000010,M = 1000010;
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
queue<int> q;
int w[220],len[220];
int G[210][210];
int far[220];
int ans;
void add(int x,int y,int z){
    ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
    ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
int Find(int x){
    if(x == far[x]) return x;
    return far[x] = Find(far[x]);
}
bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s); d[s] = 1;
    while(q.size()){
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i])
        if(edge[i] && !d[ver[i]]){
            q.push(ver[i]); d[ver[i]] = d[x] + 1;
            if(ver[i] == t) return 1;
        }
    }
    return 0;
}

int dinic(int x,ll flow){

    if(x == t) return flow;
    ll rest = flow,k;
    for(int i = head[x]; i && rest; i = Next[i]){
         if(edge[i] && d[ver[i]] == d[x] + 1){
            k = dinic(ver[i],min(rest,(ll)edge[i]));
            if(!k) d[ver[i]] = 0;
            edge[i] -= k;
            edge[i ^ 1] += k;
            rest -= k;
         }
    }
    return flow - rest;
}
int main(){
    //n = read(); m = read();
    int k; // = read();
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 0; i <= 200; i ++) far[i] = i;
    for(int i = 1; i <= m; i ++){
       //w[i] = read();len[i] = read();
       scanf("%d%d",&w[i],&len[i]);
       int fx = 0;
       for(int j = 0; j < len[i]; j ++){
//          G[i][j] = read();
          scanf("%d",&G[i][j]);
          if(G[i][j] == -1) G[i][j] = n + 2;
          if(G[i][j] == 0) G[i][j] = n + 1;
          if(j == 0) continue;

          int fy = Find(G[i][j]);
          int fx = Find(G[i][j - 1]);
          if(fx != fy) far[fx] = fy;

       }
    }
    if(Find(n + 1) != Find(n + 2))
    {printf("0
"); return 0;}

    ///地球n+1,月球n+2 起点n+3,源点n+4
    s = 0; t = 999;
    int eq = n + 1,mq = n + 2;
    tot = 1;
    ans = 0; int tt = n + 2;
    while(ans >= 0){
        add(s,ans * tt + eq,inf);
        add(ans * tt + mq,t,inf);
        if(ans != 0){
            for(int i = 1; i <= n + 2; i ++)
                add((ans - 1) * tt + i,ans * tt + i,inf);
            for(int i = 1; i <= m; i ++){
                int x = G[i][(ans - 1)%len[i]];
                int y = G[i][ans%len[i]];
                add((ans - 1) * tt + x,ans * tt + y,w[i]);
                //printf("i = %d m = %d
",i,m);
            }//printf("ok");
        }
        ll flow = 0,s1 = 0;
        while(bfs())
          while(flow = dinic(s,inf)) s1 += flow;
        sum += s1;
        if(sum >= k) break;
        ans ++;
       // printf("ans = %d
",ans);
    }
    //if(ans == 101) printf("0
");
     printf("%d
",ans);
}
/*
3
1 2 3
2
2 6
*/
///链接:https://ac.nowcoder.com/acm/contest/7831/H
/*题意:n结点树,每个结点有一颜色,两种操作,1,查询包含所有x颜色的结点最起码要多少条边
        2,修改v顶点颜色改为x;
  题解:对每种颜色的点用一个set来存,set的排序规则按照dfs序,能发现每修改一个点的颜色
  对该颜色的答案的贡献只和其在set中前后的两个点l,r有关,set中增加一个点x对答案的贡献为
  dis(l,x)+dis(x,r)−dis(l,r),删除一个点对答案的贡献为dis(l,r)−dis(l,x)−dis(x,r),能发
  现这样得到的每个颜色的答案再加上set中第一个点start和最后一个点end之间的距离
  dis(start,end)刚好是正确答案的两倍。对与每个询问答案的操作输出(ans[i]+dis(start,end))/2。
*/

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <set>
#include"queue"
#include <vector>
#define inf 107374182
#define M 10010001
#define ll long long
#define PII pair<int,int>
using namespace std;
inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}

const int N = 2001000;
int head[N],ver[N << 1],Next[N << 1],tot;
int n,m,a[N],dfn[N],top;
int f[N][22],d[N],dist[N],t;
int ans[N];
queue<int> q;
struct cmp{
    bool operator()(const int &x,const int &y) const {
        return dfn[x] < dfn[y];
    }
};
set<int,cmp> G[N];

void add(int x,int y){
    ver[++ tot] = y; Next[tot] = head[x]; head[x] = tot;
}

void bfs(){
    q.push(1); d[1] = 1;
    while(q.size()){
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i]){
            int y = ver[i];
            if(d[y]) continue;
            d[y] = d[x] + 1;
            dist[y] = dist[x] + 1;
            f[y][0] = x;
            for(int j = 1; j <= t; j ++)
                f[y][j] = f[f[y][j - 1]][j - 1];
            q.push(y);
        }
    }
}
int lca(int x,int y){
    if(d[x] > d[y]) swap(x,y);
    for(int i = t; i >= 0;i --)
        if(d[f[y][i]] >= d[x]) y = f[y][i];
    if(x == y) return x;
    for(int i = t; i >= 0;i --)
        if(f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
    return f[x][0];
}
int dis(int x,int y){
    return d[x]+d[y]-2*d[lca(x,y)];
}
void dfs(int x,int f){
    dfn[x] = ++ top;
    for(int i = head[x]; i; i = Next[i]){
        int y = ver[i];
        if(y == f) continue;
        dfs(y,x);
    }
}
void Add(int x){
    G[a[x]].insert(x);
    auto it = G[a[x]].find(x);
    int l = 0,r = 0;
    ++ it;
    if(it != G[a[x]].end()){
        r = *it;
    }
    -- it;
    if(it != G[a[x]].begin()){
        -- it;
        l = *it;
    }
    if(l && r) ans[a[x]] -= dis(l,r);
    if(l) ans[a[x]] += dis(l,x);
    if(r) ans[a[x]] += dis(x,r);
}
void Del(int x){
    auto it = G[a[x]].find(x);
    int l = 0,r = 0;
    ++ it;
    if(it != G[a[x]].end()) r = *it;
    -- it;
    if(it != G[a[x]].begin()){
        -- it;
        l = *it;
    }
    if(l && r) ans[a[x]] += dis(l,r);
    if(l) ans[a[x]] -= dis(l,x);
    if(r) ans[a[x]] -= dis(x,r);
    G[a[x]].erase(x);
}
int main(){
    n = read(); t = (int)(log(n)/log(2)) + 1;
    for(int i = 2;i <= n; i ++){
        int x = read(),y = read();
        add(x,y); add(y,x);
    }
    bfs();dfs(1,0);
    for(int i = 1; i <= n; i ++) {
        a[i] = read();
        Add(i);
    }
    m = read();
    while(m --){
        char str[2]; scanf("%s",str);
        if(str[0] == 'Q') {
            int x = read();
            if(G[x].empty()) printf("-1
");
            else if(G[x].size() == 1) printf("%d
",ans[x]);
            else printf("%d
",(ans[x] + dis(*G[x].begin(),*G[x].rbegin()))/2);
        } else {
            int x = read(),y = read();
            Del(x);a[x] = y;
            Add(x);
        }
    }
}
原文地址:https://www.cnblogs.com/yrz001030/p/13768515.html