HDU - 6393 Traffic Network in Numazu (线段树+LCA)(2018 Multi-University Training Contest 7 1008)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/81633568

Traffic Network in Numazu

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3    Accepted Submission(s): 1


 

Problem Description

Chika is elected mayor of Numazu. She needs to manage the traffic in this city. To manage the traffic is too hard for her. So she needs your help. 
You are given the map of the city —— an undirected connected weighted graph with N nodes and N edges, and you have to finish Q missions. Each mission consists of 3 integers OP, X and Y. 
When OP=0, you need to modify the weight of the Xth edge to Y. 
When OP=1, you need to calculate the length of the shortest path from node X to node Y.

 

Input

The first line contains a single integer T, the number of test cases. 
Each test case starts with a line containing two integers N and Q, the number of nodes (and edges) and the number of queries. (3≤N≤105)(1≤Q≤105) 
Each of the following N lines contain the description of the edges. The ith line represents the ith edge, which contains 3 space-separated integers ui, vi, and wi. This means that there is an undirected edge between nodes ui and vi, with a weight of wi. (1≤ui,vi≤N)(1≤wi≤105) 
Then Q lines follow, the ith line contains 3 integers OP, X and Y. The meaning has been described above.(0≤OP≤1)(1≤X≤105)(1≤Y≤105) 
It is guaranteed that the graph contains no self loops or multiple edges.

 

Output

For each test case, and for each mission whose OP=1, print one line containing one integer, the length of the shortest path between X and Y.

 

Sample Input

 

2 5 5 1 2 3 2 3 5 2 4 5 2 5 1 4 3 3 0 1 5 1 3 2 1 5 4 0 5 4 1 5 1 5 3 1 2 3 1 3 2 3 4 4 4 5 5 2 5 5 0 1 3 0 4 1 1 1 4

 

Sample Output

 

5 6 6 6

 

Source

2018 Multi-University Training Contest 7

 

Recommend

chendu

 

题意:给你一个无向联通图,有两种操作,改变某条边权值,询问X到Y的最短路径。

解题思路:注意题目条件,一共有N个节点,N条边,和图是一个无向联通图。所以突破口在只有N条边,不然就是神题了。那么我们只要忽略其中一条边(假设是第N条,两点为a,b权值为w),看成是由N-1条边组成的树,那么树上两点间的最短距离就很简单了!直接预处理+LCA即可。关键在于这题还有修改操作,那么用线段树维护一下就好了。因为当一个点被修改,它的子树里的点到根的路径都会被修改,这用DFS序+线段树维护下就好了。然后就是查询,查询分三种情况。

1.不经过第N条边 情况下的最短路径  dis(X,Y)

2.按照X->a->b->Y的路径走   dis(X,a)+dis(Y,b)+w

3.按照X->b->a->Y的路径走   dis(X,b)+dis(Y,a)+w

然后取个最小值就OK了。这里要把边拆成点,好算很多。

应该有更好地做法……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN=200005;

ll tree[MAXN<<2];//线段树数组,看你要存什么
ll lazy[MAXN<<2];

void pushdown(int rt){
    if(lazy[rt]){
        tree[rt<<1]+=lazy[rt];
        tree[rt<<1|1]+=lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}

void update(int L,int R,ll C, int l, int r, int rt){
    if(L<=l&&r<=R){
        tree[rt]+=C;
        lazy[rt]+=C;
        return;
    }
    int m=(l+r)>>1;
    pushdown(rt);
    if(L <= m) //与查询同理
        update(L,R,C,l,m,rt<<1);
    if(R > m)
        update(L,R,C,m+1,r,rt<<1|1);
}

ll query(int L,int l,int r,int rt){
    if(l==r)
        return tree[rt];
    int m=(l+r)>>1;
    pushdown(rt);
    if(L<=m)
        return query(L,l,m,rt<<1);
    else
        return query(L,m+1,r,rt<<1|1);
}

vector<int> ch[MAXN];
ll W[MAXN];
int li[MAXN],ri[MAXN];
int len=1;
void dfs1(int cn,int fa){
    li[cn]=len;
    for(int i=0;i<ch[cn].size();i++){
        if(ch[cn][i]!=fa)
            dfs1(ch[cn][i],cn);
    }
    ri[cn]=len++;
}

int N,Q;

/****LCA****/
int f[20+2][MAXN];
int dep[MAXN];
void dfs(int u,int fa)
{
    f[0][u]=fa;dep[u]=dep[fa]+1;
    for(int i=0;i<ch[u].size();++i){
        int v=ch[u][i];
        if(v==fa) continue;
        dfs(v,u);
    }
}
void lca_init(){
    memset(f,0,sizeof(f));
    dep[0]=0;
    dfs(1,0);
    for(int k=0;k+1<20;++k){
        for(int v=1;v<=N+N;++v){
            if(f[k][v]==0) f[k+1][v]=0;
            else f[k+1][v]=f[k][f[k][v]];
        }
    }
}
int LCA(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    for(int k=0;k<20;++k){
        if( (dep[v]-dep[u])>>k&1){
            v=f[k][v];
        }
    }
    if(u==v) return u;
    for(int k=20-1;k>=0;--k){
        if(f[k][u]!=f[k][v]){
            u=f[k][u];
            v=f[k][v];
        }
    }
    return f[0][u];
}
/****LCA****/

ll dis(int u,int v){
    return query(ri[u],1,len,1)+query(ri[v],1,len,1)-2*query(ri[LCA(u,v)],1,len,1);
}

int main(){
    int T;
    scanf("%d",&T);
    for(int qqq=1;qqq<=T;qqq++){
        scanf("%d%d",&N,&Q);
        len=1;
        for(int i=0;i<=N+N;i++)
            ch[i].clear();
        memset(tree,0,sizeof(tree));
        memset(lazy,0,sizeof(lazy));

        int a,b,w;
        for(int i=1;i<N;i++){
            scanf("%d%d%d",&a,&b,&w);
            W[a]=0;
            W[b]=0;
            W[N+i]=w;
            ch[a].push_back(N+i); //将边拆成点
            ch[N+i].push_back(a);
            ch[b].push_back(N+i);
            ch[N+i].push_back(b);
        }
        scanf("%d%d%d",&a,&b,&w);
        W[a]=0;
        W[b]=0;
        W[N+N]=w;

        lca_init();
        dfs1(1,0);

        for(int i=1;i<N;i++){
            update(li[N+i],ri[N+i],W[N+i],1,len,1);
            //cout<<query(ri[N+i],1,len,1)<<endl;
        }

        int X,Y,op;
        while(Q--){
            scanf("%d%d%d",&op,&X,&Y);
            if(op==0){
                if(X==N){
                    W[N+N]=Y;
                    continue;
                }
                update(li[N+X],ri[N+X],-W[N+X],1,len,1);
                W[N+X]=Y;
                update(li[N+X],ri[N+X],Y,1,len,1);
            }
            if(op==1){
                ll len1=dis(X,Y);
                ll len2=dis(X,a)+dis(Y,b)+W[N+N];
                ll len3=dis(X,b)+dis(Y,a)+W[N+N];
                //printf("%d %d %d\n",len1,len2,len3);
                printf("%lld\n",min(len1,min(len2,len3)));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/81633568