HDU 6393 Traffic Network in Numazu(LCA+思维+(树上差分)树状数组)

Traffic Network in Numazu

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


 

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

题意:这道题就是Gym - 101808K Another Shortest Path Problem(题解参考这里)+单点修改。。。

我怎么说这道题这么熟悉呢。。。给你一颗树,多一条边,每条边都有权值。两种操作:

0 x w  把第x条边(按输入顺序)的值修改为w

1 x y 查询结点x到y的最短路长度

首先任意去一条边,这里为了方便就去最后一条边,然后剩下的树求一下lca,像 Another Shortest Path Problem最后枚举一下经过和不经过你去掉的边的情况取最小值就好了。所以这里关键就是单点修改。

单点修改就用树上差分就可以了,用树状数组维护减少查询的复杂度(虽然更新的复杂度变为O(logn),但是因为有查询,整体复杂度大大降低)。维护的下标就是dfs序,然后区间更新单点查询就好了。我直接拿以前这道题的代码改,稍微加了个树状数组一下就过了。。。改变的地方都标记了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
int n,m,q,tot,tot2,cnt,tmp,ans;
int f[maxn][20];
int head[maxn];
ll dis[maxn];
int dfn[maxn],d[maxn];
int dep[maxn],e[maxn],pos[maxn];
bool vis[maxn];
int l[maxn],r[maxn],dk;//
ll w[maxn],c[maxn];//
struct node
{
    int to,nex;
    ll w;
}a[maxn];
void add(int u,int v,ll w)
{
    a[cnt].to=v;
    a[cnt].w=w;
    a[cnt].nex=head[u];
    head[u]=cnt++;
}
int lb(int x){return x&(-x);}
void init()
{
    cnt=tot=tot2=dk=0;
    memset(head,-1,sizeof(head));
    memset(pos,-1,sizeof(pos));
    memset(vis,0,sizeof(vis));
    memset(c,0,sizeof(c));
}
void dfs(int u,int deep)//1
{
    if(pos[u]!=-1)return;
    dfn[++tot2]=u;d[u]=tot2;l[u]=tot2;//
    pos[u]=tot;e[tot]=u;dep[tot++]=deep;
    for(int i=head[u];i!=-1;i=a[i].nex)
    {
        int v=a[i].to;
        if(pos[v]==-1)
        {
            dis[a[i].w]=v;// 这里十分关键,由边化点
            dfs(v,deep+1);
            e[tot]=u;dep[tot++]=deep;
        }
    }
    r[u]=tot2;
}
void rmq(int n)//2
{
    for(int i=1;i<=n;i++)f[i][0]=i;
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(1<<j)-1<=n;i++)
    {
        if(dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]) f[i][j]=f[i][j-1];
        else f[i][j]=f[i+(1<<(j-1))][j-1];
    }
}
int RMQ(int l,int r)
{
    int k=(int)(log((double)(r-l+1))/log(2.0));
    if(dep[f[l][k]]<dep[f[r-(1<<k)+1][k]]) return f[l][k];
    else return f[r-(1<<k)+1][k];
}
int lca(int x,int y)//3
{
    if(pos[x]<pos[y]) return e[RMQ(pos[x],pos[y])];
    else return e[RMQ(pos[y],pos[x])];
}
void update(int i,ll x)
{
    for(;i<=n;i+=lb(i)) c[i]+=x;
}
ll sum(int i)
{
    ll s=0;
    for(;i>0;i-=lb(i)) s+=c[i];
    return s;
}
ll cal(int x,int y)
{
    return sum(l[x])+sum(l[y])-2*sum(l[lca(x,y)]);
}
int main()
{
    int T,cas=1;
    ll W;//
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d %d",&n,&q);
        for(int i=1;i<=n-1;i++)//
        {
            int x,y;ll z;
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,i);//
            add(y,x,i);//
            w[i]=z;//
        }
        int X,Y;ll Z;
        scanf("%d%d%lld",&X,&Y,&Z);
        //printf("Case #%d:\n",cas++);
        dfs(1,0);
        rmq(2*n-1);//4
        w[n]=Z;//
        for(int i=1;i<n;i++)//
        {
            update(l[dis[i]],w[i]);//
            update(r[dis[i]]+1,-w[i]);//
        }
        ll ans=0,id;//
        while(q--)
        {
            scanf("%lld",&id);//
            if(id==0){
            int u;ll v;//
            scanf("%d %lld",&u,&v);//
            if(u==n){w[n]=v;continue;}//
            update(l[dis[u]],v-w[u]);//
            update(r[dis[u]]+1,-v+w[u]);//
            w[u]=v;//
            }
            else {
            int u,v;//
            scanf("%d %d",&u,&v);//
            ans=cal(u,v);
            ans=min(ans,cal(u,X)+cal(v,X));
            ans=min(ans,cal(u,Y)+cal(v,Y));
            ans=min(ans,cal(u,X)+cal(v,Y)+Z);
            ans=min(ans,cal(u,Y)+cal(v,X)+Z);
            printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/81661406