[Luogu] 运输计划--000

Posted shandongs1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Luogu] 运输计划--000相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problemnew/show/P2680

题解:

二分一个答案x之后,只需要考虑m条路径中路径长度大于x的那些路径,并对那些路径求一个交。设m中最长路径为l,则只需判断路径交中的边是否存在一条边e使得e.w>=l-x。如何求交?其实我们树链剖分之后,只需用一个差分数组来维护每条边被多少条路径覆盖,只需考虑被覆盖的路径条数等于当前考虑的路径条数的边即可
复杂度分析:差分数组的复杂度仅为O(1),总时间复杂度为O(nlognlogw),w<=3e8。由于差分数组和树链剖分的常数都较小,因此可以通过该题

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define clr(a,b) memset(a,b,sizeof(a))
#define maxn 300000
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
int n,m;
inline void swap(int &a,int &b) {
    int t=a;
    a=b;
    b=t;
}
struct EDGE {
    int u,v,w,next;
} edge[maxn*2+10];
int head[maxn+10],pp;
void adde(int u,int v,int w) {
    edge[++pp]=(EDGE) {
        u,v,w,head[u]
    };
    head[u]=pp;
}
int de[maxn+10],sz[maxn+10],fa[maxn+10],hs[maxn+10],w[maxn+10];
int que[maxn+10],he,ta;
vector<int>ch[maxn+10];
int top[maxn+10],id[maxn+10],s[maxn+10],tot;
void bfs() {
    que[he=ta=1]=1;
    while(he<=ta) {
        int u=que[he++];
        for(int i=head[u]; i; i=edge[i].next) {
            int v=edge[i].v;
            if(fa[u]!=v) {
                w[v]=edge[i].w;
                que[++ta]=v;
                fa[v]=u;
                de[v]=de[u]+1;
            }
        }
    }
    for(int j=ta; j; j--) {
        int u=que[j];
        sz[u]=1;
        for(int i=head[u]; i; i=edge[i].next) {
            int v=edge[i].v;
            if(fa[u]!=v) {
                sz[u]+=sz[v];
                if(sz[v]>sz[hs[u]])hs[u]=v;
            }
        }
    }
    top[1]=1;
    ch[1].push_back(1);
    for(int j=1; j<=ta; j++) {
        int u=que[j];
        for(int i=head[u]; i; i=edge[i].next) {
            int v=edge[i].v;
            if(fa[u]!=v) {
                if(v==hs[u])top[v]=top[u];
                else top[v]=v;
                ch[top[v]].push_back(v);
            }
        }
    }
    for(int u=1; u<=n; u++) {
        for(int i=0; i<ch[u].size(); i++) {
            int v=ch[u][i];
            id[v]=++tot;
            s[tot]=s[tot-1]+w[v];
        }
    }
}
void dfs1(int u) {
    sz[u]=1;
    for(int i=head[u]; i; i=edge[i].next) {
        int v=edge[i].v;
        if(v!=fa[u]) {
            fa[v]=u;
            de[v]=de[u]+1;
            w[v]=edge[i].w;
            dfs1(v);
            sz[u]+=sz[v];
            if(sz[v]>sz[hs[u]])hs[u]=v;
        }
    }
}
void dfs2(int u) {
    id[u]=++tot;
    s[tot]=s[tot-1]+w[u];
    if(hs[u]) {
        top[hs[u]]=top[u];
        dfs2(hs[u]);
    }
    for(int i=head[u]; i; i=edge[i].next) {
        int v=edge[i].v;
        if(fa[u]!=v&&v!=hs[u]) {
            top[v]=v;
            dfs2(v);
        }
    }
}
int u1[maxn+10],u2[maxn+10],d[maxn+10];
int sum(int l,int r) {
    return s[r]-s[l-1];
}
int dis(int u,int v) {
    if(u==v)return 0;
    if(top[u]==top[v]) {
        if(de[u]>de[v])swap(u,v);
        return sum(id[hs[u]],id[v]);
    }
    if(de[top[u]]>de[top[v]])swap(u,v);
    return sum(id[top[v]],id[v])+dis(u,fa[top[v]]);
}
//b为差分数组
int b[maxn+10];
void update(int l,int r) {
    b[l]++;
    b[r+1]--;
}
void modify(int u,int v) {
    if(top[v]==top[u]) {
        if(de[u]>de[v])swap(u,v);
        update(id[hs[u]],id[v]);
    } else {
        if(de[top[u]]>de[top[v]])swap(u,v);
        update(id[top[v]],id[v]);
        modify(u,fa[top[v]]);
    }
}
bool judge(int x) {
    clr(b,0);
    int cnt=0,m1=0;
    for(int i=1; i<=m; i++)if(d[i]>x) {
            cnt++;
            m1=max(m1,d[i]-x);
            modify(u1[i],u2[i]);
        }
    int tot=0,m2=0;
    for(int i=1; i<=n; i++) {
        tot+=b[i];
        if(tot==cnt)m2=max(m2,sum(i,i));
    }
    return m2>=m1;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<n; i++) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        adde(a,b,c);
        adde(b,a,c);
    }
    bfs();
    int l=0,r=0;
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&u1[i],&u2[i]);
        d[i]=dis(u1[i],u2[i]);
        r=max(r,d[i]);
    }
    int ans;
    while(l<=r) {
        int mid=(l+r)/2;
        if(judge(mid)) {
            r=mid-1;
            ans=mid;
        } else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

GG--未实现

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>

using namespace std;
const int N = 3e5 + 10;

#define gc getchar()
#define lson jd << 1
#define rson jd << 1 | 1 

int head[N], deep[N], fa[N], topp[N], son[N], tree[N], siz[N], data[N], bef[N];
struct Node {int v, w, nxt;} G[N << 1];
struct Node_2 {int l, r, dis, Max, Maxfrom;} Ask[N];
struct Node_3 {int l, r, w, Max, Maxfrom;} T[N << 2];
int n, m, now, tim, ans;

inline int read(){
    int x = 0; char c = gc;
    while(c < 0 || c > 9) c = gc;
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = gc;
    return x; 
}

inline void add(int u, int v, int w){
    G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++; 
}

void dfs_find_son(int u, int f_, int dep){
    fa[u] = f_;
    deep[u] = dep;
    siz[u] = 1;
    for(int i = head[u]; ~ i; i = G[i].nxt){
        int v = G[i].v;
        if(v != f_){
            data[v] = G[i].w;
            dfs_find_son(v, u, dep + 1);
            siz[u] += siz[v];
            if(siz[v] > siz[son[u]]) son[u] = v;
        }
    }
}

void dfs_to_un(int u, int tp){
    topp[u] = tp;
    tree[u] = ++ tim;
    bef[tim] = u;
    if(!son[u]) return ;
    dfs_to_un(son[u], tp);
    for(int i = head[u]; ~ i; i = G[i].nxt){
        int v = G[i].v;
        if(v != fa[u] && v != son[u]) dfs_to_un(v, v);
    }
}

void updata(int jd) {
    T[jd].w = T[lson].w + T[rson].w;
    T[jd].Max = max(T[lson].Max, T[rson].Max);
}

void build_tree(int l, int r, int jd){
    T[jd].l = l; T[jd].r = r;
    if(l == r) {
        T[jd].w = data[bef[l]]; 
        T[jd].Max = T[jd].w; 
        return ;
    }
    int mid = (l + r) >> 1;
    build_tree(l, mid, lson);
    build_tree(mid + 1, r, rson);
    updata(jd);
}

void Sec_A(int l, int r, int jd, int x, int y){
    if(x <= l && r <= y) {ans += T[jd].w; return ;}
    int mid = (l + r) >> 1;
    if(x <= mid) Sec_A(l, mid, lson, x, y);
    if(y > mid)  Sec_A(mid + 1, r, rson, x, y);
}

int Sec_A_imp(int x, int y){
    int tp1 = topp[x], tp2 = topp[y], answer = 0;
    while(tp1 != tp2){
        if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);
        ans = 0;
        Sec_A(1, n, 1, tree[tp1], tree[x]);
        answer += ans;
        x = fa[tp1];
        tp1 = deep[x];
    }
    if(x == y) return answer;
    ans = 0;
    if(deep[x] < deep[y]) swap(x, y);
    Sec_A(1, n, 1, tree[y] + 1, tree[x]);
    answer += ans;
    return answer;
} 

void Poi_A(int l, int r, int jd, int x, int y){
    if(x <= l && r <= y) {
        if(T[jd].Max > ans) {ans = T[jd].Max;}
        return ;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) Poi_A(l, mid, lson, x, y);
    if(y > mid)  Poi_A(mid + 1, r, rson, x, y);
}

int Poi_A_imp(int x, int y){
    int tp1 = topp[x], tp2 = topp[y], answer = 0;
    while(tp1 != tp2){
        if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);
        ans = 0;
        Poi_A(1, n, 1, tree[tp1], tree[x]);
        if(ans > answer) {answer = ans;}
        x = fa[tp1];
        tp1 = topp[x];
    }
    if(x == y) return answer;
    ans = 0;
    if(deep[x] < deep[y]) swap(x, y);
    Poi_A(1, n, 1, tree[y] + 1, tree[x]);
    answer = max(answer, ans);
    return answer;
} 

bool cmp(Node_2 a, Node_2 b){
    return a.dis > b.dis;
}

void debug(){
    for(int i = 1; i <= m; i ++) cout << Ask[i].dis << endl;cout << endl;
    for(int i = 1; i <= m; i ++) cout << Ask[i].Max << endl;
    exit(0);
}

int main()
{
    freopen("gg.in", "r", stdin);
    n = read(); m = read();
    for(int i = 1; i <= n; i ++) head[i] = -1; 
    for(int i = 1; i <= n - 1; i ++) {
        int u = read(), v = read(), w = read();
        add(u, v, w); add(v, u, w);
    }
    dfs_find_son(1, 0, 1);
    dfs_to_un(1, 1);
    build_tree(1, n, 1);
    for(int i = 1; i <= m; i ++){
        Ask[i].l = read(); Ask[i].r = read();
        Ask[i].dis = Sec_A_imp(Ask[i].l, Ask[i].r);
    }
    sort(Ask + 1, Ask + m + 1, cmp);
    int B = Ask[1].dis;
    int k = 1;
    
    while(Ask[k].dis == B){
        Ask[k].Max = Poi_A_imp(Ask[k].l, Ask[k].r);
        k ++;
    }
    //debug();
    
    for(int i = 1; i <= m; i ++){if(Ask[i].Max) Ask[i].dis -= Ask[i].Max;}
    int answer(0);
    for(int i = 1; i <= m; i ++) answer = max(answer, Ask[i].dis);
    cout << answer;
    return 0;
}
/*
6 3 
1 2 3 
1 6 4 
3 1 7 
4 3 6 
3 5 5 
3 6 
2 5 
4 5
*/

 

以上是关于[Luogu] 运输计划--000的主要内容,如果未能解决你的问题,请参考以下文章

[luogu]P2680 运输计划

luogu2680 运输计划

luogu P2680 运输计划 65分做法

[NOIP2015]运输计划

NOIP2015提高组运输计划

P2680 运输计划