zoukankan      html  css  js  c++  java
  • Codeforces Round #329 (Div. 2)D LCA+并查集路径压缩

    链接:http://codeforces.com/problemset/problem/593/D

    题意:一棵树,有边权,

    两种操作:其一,改变边权(边权只能越改越小并且大于1)。其二,给一个X(1----1e18),和a,b两点,问X / (简单路径的边权乘积)

    思路:1.裸树链剖分,维护区间乘积就可以。。爆LL的区间直接记做一个inf。。但是不太会树链剖分,考虑一个退而求其次的方法。

        2.直接跑找LCA,用到边权越来越小,所以对于边权为1的点用并查集路径压缩一下,这样就可以确保log次使得X为0或者求出来值了。

    PS。。开始还傻傻的用ST求了LCA。。其实根据上面的性质暴力求LCA就可以了。

    代码:(预处理LCA的。。虽说是多此一举。。)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN = 200010;
    int rmq[2*MAXN],tot,head[MAXN],F[MAXN*2],P[MAXN],cnt,fat[MAXN],pa[MAXN],E[MAXN][2];
    long long v[MAXN];
    
    int findset(int a) {
    	if(pa[a] != a)  return pa[a] = findset(pa[a]);
    	return pa[a];
    }
    
    void un(int a, int b){
    	int a1 = findset(a),b1 = findset(b);
    	if(a1 != b1) pa[a1] = b1;
    }
    
    struct ST{
        int mm[2*MAXN],dp[2*MAXN][20];
        void init(int n){
            mm[0] = -1;
            for(int i = 1; i <= n; i++){
                mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
                dp[i][0] = i;
            }
            for(int j = 1; j <= mm[n]; j++)
                for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
        int query(int a,int b){
            if(a > b)swap(a,b);
            int k = mm[b-a+1];
            return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
        }
    }st;
    
    struct Edge{
        int to,next;
        long long val;
    }edge[MAXN*2];
    
    void init(){
        tot = 0;
        memset(head,-1,sizeof(head));
        for(int i = 0; i < MAXN; i++)  pa[i] = i;
        memset(fat,-1,sizeof(fat));
        memset(v,-1,sizeof(v));
    }
    void addedge(int u,int v,long long c){
        edge[tot].to = v;
        edge[tot].val = c;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void dfs(int u,int pre,int dep,long long val){
        F[++cnt] = u;
        rmq[cnt] = dep;
        P[u] = cnt;
        fat[u]=pre;
        v[u]=val;
        if(u!=pre&&val==1) un(u,pre);
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(v == pre)continue;
            dfs(v,u,dep+1,edge[i].val);
            F[++cnt] = u;
            rmq[cnt] = dep;
        }
    }
    
    void LCA_init(int root,int node_num){
        cnt = 0;
        dfs(root,root,0,-1);
        st.init(2*node_num-1);
    }
    
    int query_lca(int u,int v){
        return F[st.query(P[u],P[v])];
    }
    
    int main(){
        int n,m,a,b,ttt=0,tp;
        long long c;
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<n-1;i++){
            scanf("%d%d%I64d",&a,&b,&c);
            addedge(a,b,c);
            addedge(b,a,c);
            E[++ttt][0]=a;
            E[ttt][1]=b;
        }
        LCA_init(1,n);
        for(int i=0;i<m;i++){
            scanf("%d",&tp);
            if(tp==1){
                scanf("%d%d%I64d",&a,&b,&c);
                a=findset(a);b=findset(b);
                int x=findset(query_lca(a,b));
                for(;c!=0&&a!=x;a=findset(fat[a])) c/=v[a];
                for(;c!=0&&b!=x;b=findset(fat[b])) c/=v[b];
                printf("%I64d
    ",c);
            }
            else{
                scanf("%d%I64d",&b,&c);
                if(fat[E[b][1]]==E[b][0]) swap(E[b][1],E[b][0]);
                v[E[b][0]]=c;
                if(c==1) un(E[b][0],E[b][1]);
            }
        }
        return 0;
    }
    

    精简:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN = 200010;
    int tot,head[MAXN],P[MAXN],fat[MAXN],pa[MAXN],E[MAXN][2];
    long long v[MAXN];
    
    int findset(int a) {
    	if(pa[a] != a)  return pa[a] = findset(pa[a]);
    	return pa[a];
    }
    
    void un(int a, int b){
    	int a1 = findset(a),b1 = findset(b);
    	if(a1 != b1) pa[a1] = b1;
    }
    
    struct Edge{
        int to,next;
        long long val;
    }edge[MAXN*2];
    
    void init(){
        tot = 0;
        memset(head,-1,sizeof(head));
        for(int i = 0; i < MAXN; i++)  pa[i] = i;
        memset(fat,-1,sizeof(fat));
        memset(v,-1,sizeof(v));
    }
    void addedge(int u,int v,long long c){
        edge[tot].to = v;
        edge[tot].val = c;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void dfs(int u,int pre,int dep,long long val){
        P[u] = dep;
        fat[u]=pre;
        v[u]=val;
        if(u!=pre&&val==1) un(u,pre);
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(v == pre)continue;
            dfs(v,u,dep+1,edge[i].val);
        }
    }
    
    int main(){
        int n,m,a,b,ttt=0,tp;
        long long c;
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<n-1;i++){
            scanf("%d%d%I64d",&a,&b,&c);
            addedge(a,b,c);
            addedge(b,a,c);
            E[++ttt][0]=a;
            E[ttt][1]=b;
        }
        dfs(1,1,0,-1);
        for(int i=0;i<m;i++){
            scanf("%d",&tp);
            if(tp==1){
                scanf("%d%d%I64d",&a,&b,&c);
                a=findset(a);b=findset(b);
                while(a!=b&&c!=0){
                    if(P[a]<P[b]) swap(a,b);
                    c/=v[a];
                    a=findset(fat[a]);
                }
                printf("%I64d
    ",c);
            }
            else{
                scanf("%d%I64d",&b,&c);
                if(fat[E[b][1]]==E[b][0]) swap(E[b][1],E[b][0]);
                v[E[b][0]]=c;
                if(c==1) un(E[b][0],E[b][1]);
            }
        }
        return 0;
    }
    



  • 相关阅读:
    APP热潮来临 图解九种商业模式
    Visual Studio 2010北京发布会
    高薪诚聘项目经理,架构师,高级工程师,工程师,网页设计师
    WCF闲谈:如何在流模式下传递参数
    下周股市走势预测
    明日大盘走势分析
    三步找出牛股技法
    Y COMBINATOR的六大强悍女人转自应用电台
    互联网创业公司失败的7个典型特征应用电台
    更多Windows Phone 8新功能详解
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672522.html
Copyright © 2011-2022 走看看