导航

CodeForces 593D【树链剖分】

Posted on 2015-11-27 12:13  tun~  阅读(558)  评论(0编辑  收藏  举报

题意:

给你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\n");
    else
        printf("%I64d\n",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);
            }
        }
    }
}