zoukankan      html  css  js  c++  java
  • CodeForces 593D【树链剖分】

    题意:

    给你n个点和n-1条边组成的一棵树,按顺序给出数的每一条边。

    询问m次,每次给出一个x求x除以从点a到点b所有边的权值和的乘积,还有修改,给出边的编号,修改某条边的权值。

    思路:

    树链剖分,用点的编号建立线段树,当然一开始要记录第几条边的两个端点各是什么,便于修改的时候进行查询。

    重点是用深度较大的那个点记录两个点之间的权值。

    查询的时候当两者重链的top相等的时候注意去掉top点的权值。

    然后这道题每条边的权值都是在10^18以内,所以如果线段树某个元素代表的权值之乘积大于1e18的话就直接标记成0或者别的。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int n,m;
    long long ttmp[200500];
    long long INF=1e18;
    struct bian
    {
        int a,b;
        long long c;
    };
    bian bians[200500];
    struct edge
    {
        int id;
        long long num;
        edge *next;
    };
    edge edges[200500<<1];
    edge *adj[200500];
    int ednum;
    inline void addEdge(int a,int b,long long c)
    {
        edge *tmp;
        tmp=&edges[ednum++];
        tmp->id=b;
        tmp->num=c;
        tmp->next=adj[a];
        adj[a]=tmp;
    }
    int fa[200500],top[200500],son[200500],siz[200500],id[200500],fid[200500],dep[200500];
    bool vis[200500];
    void dfs1(int me,int deep)
    {
        int maxsiz=-1;
        vis[me]=1;
        dep[me]=deep;
        siz[me]=1;
        for(edge *it=adj[me];it;it=it->next)
        {
            if(!vis[it->id])
            {
                fa[it->id]=me;
                dfs1(it->id,deep+1);
                if(maxsiz<siz[it->id])
                {
                    maxsiz=siz[it->id];
                    son[me]=it->id;
                }
                siz[me]+=siz[it->id];
            }
        }
    }
    int num;
    void dfs2(int me,int t)
    {
        vis[me]=1;
        top[me]=t;
        id[me]=++num;
        fid[num]=me;
        if(son[me])
        {
            dfs2(son[me],t);
        }
        for(edge *it=adj[me];it;it=it->next)
        {
            if(!vis[it->id])
            {
                dfs2(it->id,it->id);
            }
        }
    }
    struct tr
    {
        int s,e;
        long long num;
    };
    tr tree[200500<<2];
    long long mul(long long aaa,long long bbb)
    {
        if(aaa==0||bbb==0)
            return 0;
        if(INF/aaa<bbb)
        {
            return 0;
        }
        else
            return aaa*bbb;
    }
    void build(int k,int s,int e)
    {
        tree[k].s=s;
        tree[k].e=e;
        if(s==e)
        {
            tree[k].num=ttmp[fid[s]];
            return;
        }
        int mid=(s+e)>>1;
        build(k<<1,s,mid);
        build(k<<1|1,mid+1,e);
        tree[k].num=mul(tree[k<<1].num,tree[k<<1|1].num);
    }
    long long ans;
    void qsum(int k,int s,int e)
    {
        if(tree[k].s==s&&tree[k].e==e)
        {
            if(fid[s]==1)
                return;
            ans=mul(ans,tree[k].num);
            return;
        }
        int mid=(tree[k].s+tree[k].e)>>1;
        if(e<=mid)
        {
            qsum(k<<1,s,e);
        }
        else if(s>mid)
        {
            qsum(k<<1|1,s,e);
        }
        else
        {
            qsum(k<<1,s,mid);
            qsum(k<<1|1,mid+1,e);
        }
    }
    
    inline void print(int a,int b,long long c)
    {
        ans=1;
        int f1=top[a],f2=top[b];
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2])
            {
                swap(f1,f2);
                swap(a,b);
            }
            qsum(1,id[f1],id[a]);
            a=fa[f1];
            f1=top[a];
        }
        if(dep[a]>dep[b])
        {
            swap(a,b);
        }
        if(id[a]+1<=id[b])
        {
            qsum(1,id[a]+1,id[b]);
        }
        if(ans==0)
            printf("0
    ");
        else
            printf("%I64d
    ",c/ans);
    }
    void updat(int k,int tar,long long c)
    {
        if(tree[k].s==tree[k].e)
        {
            tree[k].num=c;
            return;
        }
        int mid=(tree[k].s+tree[k].e)>>1;
        if(tar<=mid)
        {
            updat(k<<1,tar,c);
        }
        else
        {
            updat(k<<1|1,tar,c);
        }
        tree[k].num=mul(tree[k<<1].num,tree[k<<1|1].num);
    }
    int main()
    {
        num=0;
        memset(vis,0,sizeof(vis));
        memset(son,0,sizeof(son));
        ednum=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d%I64d",&a,&b,&bians[i].c);
            bians[i].a=a;
            bians[i].b=b;
            addEdge(a,b,bians[i].c);
            addEdge(b,a,bians[i].c);
        }
        fa[1]=0;
        dfs1(1,1);
        memset(vis,0,sizeof(vis));
        dfs2(1,1);
        for(int i=1;i<n;i++)
        {
            if(dep[bians[i].a]>dep[bians[i].b])
            {
                ttmp[bians[i].a]=bians[i].c;
            }
            else
            {
                ttmp[bians[i].b]=bians[i].c;
            }
        }
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int typ,a,b;
            long long c;
            scanf("%d",&typ);
            if(typ==1)
            {
                scanf("%d%d%I64d",&a,&b,&c);
                print(a,b,c);
            }
            else
            {
                scanf("%d%I64d",&a,&c);
                if(dep[bians[a].a]<dep[bians[a].b])
                {
                    updat(1,id[bians[a].b],c);
                }
                else
                {
                    updat(1,id[bians[a].a],c);
                }
            }
        }
    }
  • 相关阅读:
    架构师的成长之路初片~ntp时间同步
    架构师的成长之路初片~水晶头的颜色排序
    架构师的成长之路初片~Python-邮件(smtplib)、requests模块、API接口调用
    架构师成长之路之~调优思维
    架构师的成长之路初片~python~调整背景及滚轮+各种快捷键
    架构师成长之路之~Node.js安装篇
    微服务技术栈
    C#资源释放(托管资源、非托管资源)
    Beyond Compare 4 密匙
    MySql批量导入 .netcore命名空间完全相同问题
  • 原文地址:https://www.cnblogs.com/tun117/p/5000277.html
Copyright © 2011-2022 走看看