2016 ACM/ICPC Asia Regional Shenyang Online HDU 5893 List wants to travel

本文介绍了一种基于树状结构的高效查询与更新算法,适用于解决路径上的颜色变化及统计问题。通过离线预处理建立数据结构,实现快速响应查询与更新操作。

List wants to travel

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 331    Accepted Submission(s): 66


Problem Description
A boy named List who is perfect in English. Now he wants to travel and he is making a plan. But the cost of living in same citie always changes. Now he wants to know how many different kinds of continuous same cost he has to pay for living between two cities. Can you help him? (He is so lazy to do this by himself.)
 

Input
There are multiple cases. The first line contains two positive numbers N and M(N (N<=40000) where N is the amount of cities and M (M<=50000)) is the amount of operations.Then N-1 lines where each line have 3 integers a b and c, representing that there is a bidirectionoal road between city a and city b, and the cost is c.(a != b and c <= 100000). Then there are M lines of operation. For example, "Change a b c" means changing all the costs of the road which are passed by him when he travels from city a to city b to c. "Query a b" means he wants you to tell him how many different kinds of continuous same cost he has to pay traveling from city a to city b.(if a == b, the cost is 0).
 

Output
He insure you that there is exactly one route between every two different cities.
 

Sample Input
  
9 3 1 2 2 2 3 1 1 7 2 1 4 2 3 5 2 3 6 1 5 8 2 5 9 3 Query 1 8 Change 2 6 3 Query 1 6
 

Sample Output
  
3 2
 【题意】一颗无根树,两种操作:改变路径上的颜色,和询问路径上有多少段颜色。

【解题方法】算是bzoj原题了。。。bzoj 2243,不过bzoj上是点权,这里是边权,改一下就可以A了。这题之前写过,当时参考了这篇blog:http://blog.youkuaiyun.com/viphong/article/details/52167628

【具体分析】

原题是 点权,那么只需要查询时,判断当前链的顶端与链子的顶端的父亲是否同色即可。(或者判断链子的末端与last链的top是否同色),而现在是边权,则我们分开判断lca(u,v)对应的两条链即可即 。 int lastu=-1,col,lastv=-1;对于 查询一条 f1到u的链,求u的颜色   col=query_col(1,1,pos,p[u]);if (col==lastu) tmp--;最后u和v在一条链时,分别判断  u和lastu,v和lastv是否相等 (if u==v只判断一次即可)

【AC 代码】

//
//Created by just_sort 2016/9/12 17:37
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100050;
struct Edge
{
    int to,next,w;
    Edge(){}
    Edge(int a,int b,int c){to=a,next=b,w=c;}
}edge[maxn*2],tmp[maxn];
int head[maxn],tot,n,m,top[maxn],fa[maxn],dep[maxn],num[maxn],tid[maxn],son[maxn],tim;
void init(){
    tot = tim = 0;
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
}
void addedge(int u,int v,int w){
    edge[tot]={v,head[u],w};
    head[u] = tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v != pre)
        {
            dfs1(v,u,d+1);
            num[u] += num[v];
            if(son[u] == -1 || num[v] > num[son[u]])
                son[u] = v;
        }
    }
}
void dfs2(int u,int tp)
{
    top[u] = tp;
    tid[u] = ++tim;
    if(son[u]!=-1)
        dfs2(son[u],tp);
    for(int i = head[u] ; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v != son[u] && v != fa[u])
            dfs2(v,v);
    }
}
struct SegmentTree
{
    int sum[4*maxn],add[4*maxn], numl[maxn*4], numr[maxn*4];
    void init()
    {
        memset(sum,0,sizeof sum);
        memset(add,0,sizeof add);
        memset(numl,0,sizeof numl);
        memset(numr,0,sizeof numr);
    }
    void build(int l,int r,int rt)
    {
        add[rt] = -1;
        sum[rt] = 0;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
    }
    void pushUp(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1]-(numr[rt<<1]==numl[rt<<1|1]);
        numl[rt]=numl[rt<<1];
        numr[rt]=numr[rt<<1|1];
    }
    void pushDown(int rt, int l, int r)
    {
        if(add[rt] != -1)
        {
            add[rt<<1]=add[rt<<1|1]=add[rt];
            numl[rt<<1]=numl[rt<<1|1]=add[rt];
            numr[rt<<1]=numr[rt<<1|1]=add[rt];
            sum[rt<<1]=sum[rt<<1|1]=1;
            add[rt]=-1;
        }
    }
    void update(int rt, int l, int r, int L,int R, int c)
    {
        if(l > R || L > r)
            return ;
        if(l >=L && r <=R )
        {
            sum[rt]=1;
            add[rt]=numl[rt]=numr[rt]=c;
            return ;
        }
        pushDown(rt, l, r);
        int mid = (l + r) >> 1;
        update(rt << 1, l, mid, L,R, c);
        update(rt << 1 | 1, mid + 1, r, L,R, c);
        pushUp(rt);
    }

    int query(int rt, int l, int r, int L, int R)
    {
        if(l > R || L > r)
            return 0;
        if(l >= L && r <= R)
            return sum[rt];
        pushDown(rt, l, r);
        int m=(l+r)/2;
        int ret=0;
        if(L<=m) ret+=query(rt<<1,l,m,L,R);
        if(m<R) ret+=query(rt<<1|1,m+1,r,L,R);
        if(L<=m&&m<R) ret-=(numr[rt<<1]==numl[rt<<1|1]);
        return ret;
    }
    int querycol(int rt, int l, int r, int x)
    {
        if(l==r)  return add[rt];
        pushDown(rt, l, r);
        int m=(l+r)/2;
        if(x<=m) return querycol(rt<<1,l,m,x);
        return querycol(rt<<1|1,m+1,r,x);
    }
    int queryans(int u,int v)
    {
        int f1=top[u],f2=top[v];
        int tmp=0;
        int cur;
        int lastu=-1,lastv=-1;
        while(f1!=f2)
        {
            if (dep[f1]<dep[f2]){
                swap(f1,f2);
                swap(u,v);
                swap(lastu,lastv);
            }
            tmp+=query(1,1,tim,tid[f1],tid[u]);
            cur=querycol(1,1,tim,tid[u]);
            if (cur==lastu) tmp--;
            lastu=querycol(1,1,tim,tid[f1]);
            u=fa[f1],f1=top[u];
        }
        if (u!=v)
        {
            if (dep[u]>dep[v] ) swap(u,v),swap(lastu,lastv);
            tmp+=query(1,1,tim,tid[son[u]],tid[v]);
            cur=querycol(1,1,tim,tid[v]);
            if (cur==lastv) tmp--;
            cur=querycol(1,1,tim,tid[son[u]]);
            if (cur==lastu) tmp--;
        }
        else if (lastu==lastv) tmp--;
        return  tmp;
    }
    void negnate(int u,int v,int c)
    {
        int f1=top[u],f2=top[v];
        while(f1!=f2)
        {
            if (dep[f1]<dep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
            update(1,1,tim,tid[f1],tid[u],c);
            u=fa[f1],f1=top[u];
        }
        if (dep[u]>dep[v] ) swap(u,v);
        if (u!=v)
            update(1,1,tim,tid[son[u]],tid[v],c);
    }
}tree;
int main()
{
    int u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        tree.init();
        for (int i=1; i<n; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
            tmp[i]=Edge(u,v,w);
        }
        dfs1(1,0,0);
        dfs2(1,1);
        tree.build(1,tim,1);
        for (int i=1; i<n; i++)
        {
            u=tmp[i].next,v=tmp[i].to,w=tmp[i].w;
            if (fa[u]==v) tree.update(1,1,tim,tid[u],tid[u],w);
            else tree.update(1,1,tim,tid[v],tid[v],w);
        }
        char op[10];
        for (int i=1; i<=m; i++)
        {
            scanf("%s%d%d",op,&u,&v);
            if (op[0]=='Q'){
                if(u==v) printf("0\n");
                else printf("%d\n",tree.queryans(u,v));
            }
            else{
                scanf("%d",&w);
                tree.negnate(u,v,w);
            }
        }
    }
    return 0;
}




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值