Codeforces Round #329 (Div. 2) 593D. Happy Tree Party(树链剖分)

题意:给你一棵树,每条边上有权值。有两个操作
1. u v p 从u~v的路径上用p除每跳边的权值,向下取整
2. u p 将第u条边的权值改为p
思路:树链剖分 呃…算是模板题吧 因为这道题学了十几个小时的树链剖分
照着卿神的blog理解的Orz 卿神blog

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define sfor(i,a,h) for(i=h[a];i!=-1;i=e[i].next)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
#define cheak(i) printf("%d ",i)
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define inf 0x3f3f3f3f
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 200005
#define maxm maxn*maxn
#define lson(x) (splay[x].son[0])
#define rson(x) (splay[x].son[1])
const long long kkk=1e18+10;
struct node
{
    int next,sta,to;
    LL val;
}e[maxn*2],tmp[maxn];
int tot,tim,h[maxn],n,m;
int fa[maxn],son[maxn];
int top[maxn],siz[maxn],Rank[maxn];
int dep[maxn],tid[maxn];
LL A[maxn];
void add_edge(int a,int b,int c)
{
    e[++tot].next=h[a];
    e[tot].sta=a;
    e[tot].to=b;
    e[tot].val=c;
    h[a]=tot;
}
void start()
{
    mem(h,-1);mem(son,-1);
    tot=0,tim=0;
}
//树链剖分
void dfs1(int u,int father,int d)
{
    //printf("**%d %d %d\n",u,father,d);
    fa[u]=father;
    dep[u]=d;
    siz[u]=1;
    for(int i=h[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=father)
        {
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[u]==-1||siz[v]>siz[son[u]])
            son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{
    //printf("++%d %d\n",u,tp);
    tid[u]=++tim;
    Rank[tim]=u;
    top[u]=tp;
    if(son[u]==-1) return ;
    dfs2(son[u],tp);
    for(int i=h[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa[u]&&v!=son[u])
        dfs2(v,v);
    }
}
//线段树
struct Segment
{
    LL val,lazy;
}tree[maxn*4];
void Push_up(int index)
{
    if(tree[index*2].val==0) tree[index].val=1;
    if(tree[index*2+1].val==0) tree[index].val=1;
    double x1=tree[index*2].val;
    double x2=tree[index*2+1].val;
    if(log(x1)+log(x2)>log(kkk*1.0))
    tree[index].val=kkk+5;
    else
    tree[index].val=tree[index*2].val*tree[index*2+1].val;
}
void build(int l,int r,int index)
{
    tree[index].val=1;
    if(l==r)
    {
        tree[index].val=A[l];
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,index*2);
    build(mid+1,r,index*2+1);
    Push_up(index);
}
void update(int l,int r,int x,LL val,int index)
{
    if(l==r)
    {
        tree[index].val=val;
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid) update(l,mid,x,val,index*2);
    else update(mid+1,r,x,val,index*2+1);
    Push_up(index);
}
LL query(int l,int r,int L,int R,int index)
{
    //printf("****%d %d %d %d %d\n",l,r,L,R,index);
    if(L<=l&&r<=R) return tree[index].val;
    int mid=(l+r)/2;
    LL ans=1;
    if(L<=mid)
    {
        LL x=query(l,mid,L,R,index*2);
        //printf("@@@%lld\n",x); 
        if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))//判断是否大于1e18 如果大于直接等于1e18+正整数 因为答案肯定是0 
        ans=kkk+203;
        else ans*=x;
    }
    if(R>mid)
    {
        LL x=query(mid+1,r,L,R,index*2+1);
        //printf("@@%lld\n",x);
        if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
        ans=kkk+203;
        else ans*=x;
    }
    return ans;
}
LL solve1(int u,int v)
{
    LL ans=1;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        //printf("**%d %d\n",tid[top[u]],tid[u]);
        LL x=query(2,n,tid[top[u]],tid[u],1);
        //printf("+++%lld\n",x);
        if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
        ans=kkk+203;
        else ans*=x;
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    if(u!=v)
    {
        //printf("%d %d\n",tid[u]+1,tid[v]);
        LL x=query(2,n,tid[u]+1,tid[v],1);
        //printf("++++%lld\n",x);
        if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
        ans=kkk+203;
        else ans*=x;
    }
    return ans;
}
void solve2(int i,LL val)
{
    if(dep[tmp[i].sta]>dep[tmp[i].to])
    update(2,n,tid[tmp[i].sta],val,1);
    else update(2,n,tid[tmp[i].to],val,1);
}
int main()
{
    int k,i,u,v,oper;
    LL x;
    start();
    scanf("%d%d",&n,&k);
    rfor(i,1,n-1)
    {
        scanf("%d%d%lld",&u,&v,&x);
        tmp[i].sta=u,tmp[i].to=v,tmp[i].val=x;
        add_edge(u,v,x);add_edge(v,u,x);    
    }
    dfs1(1,0,0);
    dfs2(1,1);
    rfor(i,1,n-1)
    {
        if(dep[tmp[i].sta]>dep[tmp[i].to])
        A[tid[tmp[i].sta]]=tmp[i].val;
        else A[tid[tmp[i].to]]=tmp[i].val;
    }
    build(2,n,1);
    while(k--)
    {
        scanf("%d",&oper);
        if(oper==1)
        {
            scanf("%d%d%lld",&u,&v,&x);
            printf("%lld\n",x/solve1(u,v));
        }
        else
        {
            scanf("%d%lld",&i,&x);
            solve2(i,x);
        }
    }
    return 0;
}

你可能感兴趣的:(codeforces,树链剖分)