zoukankan      html  css  js  c++  java
  • CF #329 D

    D题,LCA是很明显的。要注意的是,因为是除法,所以最多可以除x>2的有64次,当大于64时可以直接返回0。而且注意到可能会有很多值为1的边,可以使用路径压缩,把边为1的边压缩掉,类似于并查集的路径压缩。

    之前只压缩到LCA,一直TLE,可以直接压缩到它们的根节点。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    #define LL long long
    using namespace std;
    
    const int MAX=200050;
    
    int head[MAX],tot;
    struct Edge{
        int u,v,next;
        LL w;
    }edge[MAX*2];
    LL w[MAX]; int pre[MAX],depth[MAX],edno[MAX],par[MAX][20];
    bool vis[MAX];
    queue<int>que;
    
    void addedge(int u,int v,LL w){
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    int n,m;
    
    void BFS(int u){
        que.push(u);
        depth[u]=1;
        edno[u]=0;
        while(!que.empty()){
            u=que.front();
            vis[u]=true;
            que.pop();
            for(int e=head[u];e!=-1;e=edge[e].next){
                int v=edge[e].v;
                if(vis[v]) continue;
                depth[v]=depth[u]+1;
                par[v][0]=u;        
                if(w[edno[u]]==1){
                    pre[v]=pre[u];
                    edno[v]=edge[e].w;
                }
                else{
                    pre[v]=u;
                    edno[v]=edge[e].w;
                }
                que.push(v);
            }
        }
    }
    
    void init(){
        int i,j;
        for(j=1;(1<<j)<=n;j++)
            for(i=1;i<=n;i++)
                if(par[i][j-1]!=-1)
                    par[i][j]=par[par[i][j-1]][j-1];
    }
    
    int LCA(int a,int b)//最近公共祖先
    {
        int i,j;
        if(depth[a]<depth[b])swap(a,b);
        for(i=0;(1<<i)<=depth[a];i++);
            i--;
          //使a,b两点的深度相同
        for(j=i;j>=0;j--)
            if(depth[a]-(1<<j)>=depth[b])
              a=par[a][j];
            if(a==b)return a;
          //倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
        for(j=i;j>=0;j--){
            if(par[a][j]!=-1&&par[a][j]!=par[b][j]){
              a=par[a][j];
              b=par[b][j];
            }
        }
        return par[a][0];
    }
    
    LL anum[70];
    LL bnum[70];
    
    
    LL query(int a,int b,LL y){
        int ret=(int)(log((double)y)/log(2.0));
        int lca=LCA(a,b);
    /// cout<<lca<<" "<<ret<<endl;
        int ac=0,bc=0;
        while(a!=-1&&depth[a]>depth[lca]){
    ////        cout<<a<<" "<<w[edno[a]]<<endl;
            if(w[edno[a]]>1){
                y/=w[edno[a]];
                if(y==0) return 0;
            }
            int tp=pre[a];
            while(pre[tp]!=-1&&w[edno[tp]]==1){
                tp=pre[tp];
            }
            int rt=tp; tp=a;
            while(pre[tp]!=rt){
                int tmp=pre[tp];
                pre[tp]=rt;
                tp=tmp;
            }
            a=rt;
        }
        LL ty=y;
        while(b!=-1&&depth[b]>depth[lca]){
    ///     cout<<b<<" "<<edno[b]<<endl;
            if(w[edno[b]]>1){
                ty/=w[edno[b]];
                bnum[bc++]=w[edno[b]];
                if(ty==0) return 0;
            }
            int tp=pre[b];
            while(pre[tp]!=-1&&w[edno[tp]]==1){
                tp=pre[tp];
            }
            int rt=tp; tp=b;
            while(pre[tp]!=rt){
                int tmp=pre[tp];
                pre[tp]=rt;
                tp=tmp;
            }
            b=rt;
        }
    /// cout<<ac<<" "<<bc<<endl;
    /// cout<<bnum[bc-1]<<endl;
    /// for(int i=0;i<ac;i++) y/=anum[i];
        for(int i=bc-1;i>=0;i--) y/=bnum[i];
        return y;
    }
    
    
    int main(){
        int u,v,op,a,b,p,c;
        LL y;
        while(scanf("%d%d",&n,&m)!=EOF){
            memset(pre,-1,sizeof(pre));
            memset(head,-1,sizeof(head));
            memset(depth,0,sizeof(depth));
            memset(vis,false,sizeof(vis));
            memset(w,0,sizeof(w));
            memset(par,-1,sizeof(par));
            memset(edno,0,sizeof(edno));
            tot=0;
            for(int i=1;i<n;i++){
                cin>>u>>v>>w[i];
                addedge(u,v,i);
                addedge(v,u,i);
            }
            BFS(1);
        /// cout<<pre[2]<<" "<<edno[2]<<endl;
            init();
            for(int i=1;i<=m;i++){
                scanf("%d",&op);
                if(op==1){
                    cin>>a>>b>>y;
                    cout<<query(a,b,y)<<endl;
                }
                else{
                    cin>>p>>y;
                    w[p]=y;
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    【操作系统】用Oracle VM VirtualBox 虚拟机安装XP系统时老是蓝屏
    c#操作Xml(六)
    c#操作Xml(五)
    c#操作Xml(三)
    c#操作Xml(四)
    新年快乐
    c#操作Xml(八)
    从IDataReader中读取数据实体
    c#操作Xml(七)
    c#操作Xml(二)
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4957764.html
Copyright © 2011-2022 走看看