zoukankan      html  css  js  c++  java
  • hihocoder-1347 小h的树上的朋友(lca+线段树)

    题目链接:

    小h的树上的朋友

    时间限制:18000ms
    单点时限:2000ms
    内存限制:512MB

    描述

    小h拥有n位朋友。每位朋友拥有一个数值Vi代表他与小h的亲密度。亲密度有可能发生变化。

    岁月流逝,小h的朋友们形成了一种稳定的树状关系。每位朋友恰好对应树上的一个节点。

    每次小h想请两位朋友一起聚餐,他都必须把连接两位朋友的路径上的所有朋友都一起邀请上。并且聚餐的花费是这条路径上所有朋友的亲密度乘积。

    小h很苦恼,他需要知道每一次聚餐的花销。小h问小y,小y当然会了,他想考考你。

    输入

    输入文件第一行是一个整数n,表示朋友的数目,从1开始编号。

    输入文件第二行是n个正整数Vi,表示每位朋友的初始的亲密度。

    接下来n-1行,每行两个整数u和v,表示u和v有一条边。

    然后是一个整数m,代表操作的数目。每次操作为两者之一:

    0 u v 询问邀请朋友u和v聚餐的花费

    1 u v 改变朋友u的亲密度为v

    1<=n,m<=5*105

    Vi<=109

    输出

    对于每一次询问操作,你需要输出一个整数,表示聚餐所需的花费。你的答案应该模1,000,000,007输出。

    样例输入
    3
    1 2 3
    1 2
    2 3
    5
    0 1 2
    0 1 3
    1 2 3
    1 3 5
    0 1 3
    样例输出
    2
    6
    15
    题意:
    中文的就不说了;

    思路:
    显然是一个线段树的题;
    先dfs,把树映射到区间上同时求出每个点到根节点的花费,
    0的时候询问:先找到lca;再dis[u]*dis[v]*w[lca]/(dis[lca]*dis[lca]);可以费马小定理快速幂求逆;
    1的时候更新:dfs的时候找到了每个点的包含此点所以子节点的区间,把这个区间的dis都更新同时还要更新w[u]我就是这两个问题写漏了改了一夜晚;

    AC代码:

    #include <bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    #define For(i,j,n) for(int i=j;i<=n;i++)
    #define mst(ss,b) memset(ss,b,sizeof(ss));
    
    typedef  long long LL;
    
    template<class T> void read(T&num) {
        char CH; bool F=false;
        for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
        for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
        F && (num=-num);
    }
    int stk[70], tp;
    template<class T> inline void print(T p) {
        if(!p) { puts("0"); return; }
        while(p) stk[++ tp] = p%10, p/=10;
        while(tp) putchar(stk[tp--] + '0');
        putchar('
    ');
    }
    
    const LL mod=1e9+7;
    const double PI=acos(-1.0);
    const int inf=1e9;
    const int N=5e5+10;
    const int maxn=1e3+10;
    const double eps=1e-10;
    
    LL w[N],dis[N];
    vector<int>ve[N];
    
    int n,in[N],a[2*N],dep[N],cnt=0,out[N];
    
    LL pow_mod(LL x,LL y)
    {
        LL s=1,base=x;
        while(y)
        {
            if(y&1)s=s*base%mod;
            base=base*base%mod;
            y>>=1;
        }
        return s;
    }
    
    void dfs(int x,int deep,int fa)
    {
        cnt++;
        in[x]=cnt;
        a[cnt]=x;
        dep[x]=deep;
        int len=ve[x].size();
        For(i,0,len-1)
        {
            int y=ve[x][i];
            if(y==fa)continue;
            dis[y]=dis[x]*w[y]%mod;
            dfs(y,deep+1,x);
            cnt++;
            a[cnt]=x;
        }
        out[x]=cnt;
    }
    struct Tree
    {
        int l,r,lca;
        LL dis;
    }tr[8*N];
    void pushdown(int o)
    {
        tr[2*o].dis=tr[2*o].dis*tr[o].dis%mod;
        tr[2*o+1].dis=tr[2*o+1].dis*tr[o].dis%mod;
        tr[o].dis=1;
    }
    void build(int o,int L,int R)
    {
        tr[o].l=L;
        tr[o].r=R;
        tr[o].dis=1;
        if(L==R)
        {
            tr[o].dis=dis[a[L]];
            tr[o].lca=a[L];
            return ;
        }
        int mid=(L+R)>>1;
        build(2*o,L,mid);
        build(2*o+1,mid+1,R);
        if(dep[tr[2*o].lca]>=dep[tr[2*o+1].lca])tr[o].lca=tr[2*o+1].lca;
        else tr[o].lca=tr[2*o].lca;
    }
    void update(int o,int L,int R,LL val)
    {
        if(tr[o].l>=L&&tr[o].r<=R)
        {
            tr[o].dis=tr[o].dis*val%mod;
            return ;
        }
        int mid=(tr[o].l+tr[o].r)>>1;
    
        if(L>mid)update(2*o+1,L,R,val);
        else if(R<=mid)update(2*o,L,R,val);
        else {
            update(2*o,L,mid,val);
            update(2*o+1,mid+1,R,val);
        }
    }
    int querylca(int o,int L,int R)
    {
    
            if(tr[o].l>=L&&tr[o].r<=R)return tr[o].lca;
            int mid=(tr[o].l+tr[o].r)>>1;
            if(R<=mid)return querylca(2*o,L,R);
            else if(L>mid)return querylca(2*o+1,L,R);
            else 
            {
                int fl=querylca(2*o,L,mid),fr=querylca(2*o+1,mid+1,R);
                if(dep[fl]<=dep[fr])return fl;
                else return fr;
            }
    }
    LL query(int o,int pos)
    {
        if(tr[o].l==tr[o].r&&tr[o].l==pos)return tr[o].dis;
        int mid=(tr[o].l+tr[o].r)>>1;
        pushdown(o);
        if(pos>mid)return query(2*o+1,pos);
        return query(2*o,pos);
    }
    int main()
    {
            read(n);
            For(i,1,n)read(w[i]);
            int u,v;
            For(i,1,n-1)
            {
                read(u);read(v);
                ve[u].push_back(v);
                ve[v].push_back(u);
            }
            dis[1]=w[1];
            dfs(1,0,0);
            build(1,1,cnt);
            int q,f;
            read(q);
            while(q--)
            {
                read(f);read(u);read(v);
                if(f)
                {
                    LL temp=w[u];
                    w[u]=(LL)v;
                    update(1,in[u],out[u],w[u]*pow_mod(temp,mod-2)%mod);
                }
                else
                {
                    if(in[u]>in[v])swap(u,v);
                    int lca=querylca(1,in[u],in[v]);
                    LL temp=query(1,in[lca]);
                    temp=pow_mod(temp,mod-2);
                    temp=temp*temp%mod;
                    LL ans=query(1,in[u])*query(1,in[v])%mod*temp%mod*w[lca]%mod;
                    cout<<ans<<"
    ";
                }
            }        
            return 0;
    }
    

      

  • 相关阅读:
    【原】【Git】EGit强制覆盖本地文件
    【EGit】The current branch is not configured for pull No value for key branch.master.merge found in config
    【转】【Egit】如何将eclipse中的项目上传至Git
    参加SAP VT项目有感
    2013_12_30 纪念
    2013 12 25 圣诞日
    gin系列-中间件
    gin系列- 路由及路由组
    gin系列-重定向
    gin系列-文件上传
  • 原文地址:https://www.cnblogs.com/zhangchengc919/p/5677538.html
Copyright © 2011-2022 走看看