zoukankan      html  css  js  c++  java
  • csp-s测试41 T2 影子

    1、并查集

    可以并查集:
    考虑对点权的限制。
    尝试逐点枚举点权,向点权大于等于自己的节点扩展,计算最大路径。
    优化:瓶颈在于还是有很多重复的。
    上述的每个节点扩展后形成的连通块点集成为一个集合,
    从大点权到小点权只要集合拓展。
    维护集合:考虑并查集
    点权排序,维护集合内最长链即可。

    nlog

    #include<bits/stdc++.h>
    #define F(i,a,b) for(rg int i=a;i<=b;++i)
    #define rg register
    #define LL long long
    #define il inline
    #define pf(a) printf("%d ",a)
    #define phn puts("")
    using namespace std;
    #define int LL
    int read();
    /*
    可以并查集:
    考虑对点权的限制。
    尝试逐点枚举点权,向点权大于等于自己的节点扩展,计算最大路径。
    优化:瓶颈在于还是有很多重复的。
    上述的每个节点扩展后形成的连通块点集成为一个集合,
    从大点权到小点权只要集合拓展。
    维护集合:考虑并查集
    点权排序,维护集合内最长链即可。
    */
    #define N 100010
    int n;
    int to[N<<1],fir[N<<1],len[N<<1],head[N],cnt;
    int val[N];
    int f[N][20],s[N],d[N];
    il int max(int x,int y){return x>y?x:y;}
    il void add(int x,int y,int w){to[++cnt]=y;fir[cnt]=head[x];head[x]=cnt;len[cnt]=w;}
    void dfs(int x,int fa){
        f[x][0]=fa;d[x]=d[fa]+1;
        F(i,1,18)f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x];i;i=fir[i]){
            int v=to[i];
            if(v!=fa)s[v]=s[x]+len[i],dfs(v,x);
        }
    }
    il int lca(int x,int y){
        if(d[x]<d[y])swap(x,y);
        for(int i=18;~i;--i)if(d[f[x][i]]>=d[y])x=f[x][i];
        if(x==y)return x;
        for(int i=18;~i;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    struct node{
        int x,w;
        friend bool operator < (node a,node b){return a.w>b.w;}
    }a[N];
    int jh[N],w[N],dl[N],dr[N];
    bool vis[N];
    LL ans;
    int find(int x){return jh[x]==x?x:jh[x]=find(jh[x]);}
    il int hb(int x,int y){
        x=find(x),y=find(y);
        if(x==y)return x;
        int a[2]={dl[x],dr[x]},b[2]={dl[y],dr[y]};
        int mxd=w[y],l=dl[y],r=dr[y];
        F(i,0,1){
            F(j,0,1){
                int dis=s[a[i]]+s[b[j]]-2ll*s[lca(a[i],b[j])];
                if(dis>mxd){
                    mxd=dis;l=a[i];r=b[j];
                }
            }
        }
        if(mxd>w[x]){
            w[x]=mxd;dl[x]=l;dr[x]=r;
        }
        jh[y]=x;
        return x;
    }
    signed main(){
    //    freopen("b.in","r",stdin);
        int T=read();
        while(T--){
            cnt=0;memset(head,0,sizeof(head));ans=0;
            n=read();
            F(i,1,n)a[i]=(node){i,read()};
            for(rg int i=2,u,v,val;i<=n;++i)
                u=read(),v=read(),val=read(),add(u,v,val),add(v,u,val);
            dfs(1,0);
            sort(a+1,a+n+1);
            ans=0;
            F(i,1,n){
                 jh[i]=i;w[i]=vis[i]=0;dl[i]=dr[i]=i;
            }
            rg int u;
            F(i,1,n){
                u=a[i].x;vis[u]=1;
                for(rg int j=head[u];j;j=fir[j]){
                    int v=to[j];
                    if(vis[v]){
                        int rt=hb(u,v);
                        ans=max(ans,w[rt]*a[i].w);
                    }
                }
            }
            printf("%lld
    ",ans);//
        }
    }
    il int read(){
        rg int s=0;rg char ch;
        while(ch=getchar(),!isdigit(ch));
        for(;isdigit(ch);s=s*10+(ch^48),ch=getchar());
        return s;
    }
    /*
    g++ 1.cpp -g
    time ./a.out
    1
    3
    1 2 3
    1 2 1
    1 3 2
    */
    View Code

     2、点分治。

    也是对上述暴力的优化。

    nlog*log,点分×set (第二个log是log当前点儿子。常数小。)

    维护当前分治子树内各点的到根距离、min点权。

    然后按最小点权大到小sort记录的信息,更新max边,用当前点×max边。

    为了避免来自同一子树,要记录该点所属的根的儿子是谁。

    multiset维护各儿子当前max边。

    wmz用了线段树做set的功能。但是没必要,增加了常数和码量。不如multiset。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define lch p<<1
    #define rch p<<1|1
    using namespace std;
    const int N=1e5+7;
    const int inf=0x7f7f7f7f;
    struct node{
        long long mx;
        bool clear;
    }s[N<<2];
    inline void down(int p){
        if(!s[p].clear) return ;
        s[lch].clear=s[rch].clear=1;
        s[lch].mx=s[rch].mx=0;
        s[p].clear=0;
    }
    inline void up(int p){
        s[p].mx=max(s[lch].mx,s[rch].mx);
    }
    void insert(int p,int l,int r,int pos,long long val){
        if(l==r) return (void)(s[p].mx=max(s[p].mx,val));
        down(p);
        int mid=l+r>>1;
        if(pos<=mid) insert(lch,l,mid,pos,val);
        else insert(rch,mid+1,r,pos,val);
        up(p);
    }
    long long query(int p,int l,int r,int L,int R){
        if(l>=L&&r<=R) return s[p].mx;
        down(p);
        int mid=l+r>>1;
        long long ans=0;
        if(L<=mid) ans=max(query(lch,l,mid,L,R),ans);
        if(R>mid) ans=max(query(rch,mid+1,r,L,R),ans);
        up(p);
        return ans;
    }
    struct data{
        int mn,k;
        long long sum;
        data(){}
        data(int mn,long long sum,int k):mn(mn),sum(sum),k(k){}
        inline friend bool operator < (const data &a,const data &b){
            return a.mn>b.mn;
        }
    }que[N];
    int n,tot,root,sumsz,mn,cnt;
    bool v[N];
    int head[N],nxt[N<<1],to[N<<1],w[N<<1],d[N],sz[N];
    long long ans;
    void calc(int x,int from,int mn,long long sum,int k){
        mn=min(mn,d[x]);
        ans=max(ans,sum*mn);
        que[++cnt]=data(mn,sum,k);
        for(int i=head[x];i;i=nxt[i])
            if(!v[to[i]]&&to[i]!=from) calc(to[i],x,mn,sum+w[i],k);
    }
    void findroot(int x,int from,int mxp=0){
        sz[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            if(to[i]==from||v[to[i]]) continue;
            findroot(to[i],x);
            sz[x]+=sz[to[i]];
            if(sz[to[i]]>mxp) mxp=sz[to[i]];
        }
        if(sumsz-sz[x]>mxp) mxp=sumsz-sz[x];
        if(mxp<mn) mn=mxp,root=x;
    }
    void solve(int x,int num=0){
        v[x]=1; cnt=0;
        for(int i=head[x];i;i=nxt[i])
            if(!v[to[i]]) calc(to[i],x,d[x],w[i],++num);
        sort(que+1,que+cnt+1);
        for(int i=1;i<=cnt;++i){
            if(i!=1){
                long long sum=0;
                if(que[i].k!=1) sum=max(sum,query(1,1,num,1,que[i].k-1));
                if(que[i].k!=num) sum=max(sum,query(1,1,num,que[i].k+1,num));
                ans=max(ans,que[i].mn*(sum+que[i].sum));
            }
            insert(1,1,num,que[i].k,que[i].sum);
        }
        s[1].clear=1;
        for(int i=head[x];i;i=nxt[i]){
            if(v[to[i]]) continue;
            sumsz=sz[to[i]]; mn=N;
            findroot(to[i],x);
            solve(root);
        }
    }
    inline void add(int a,int b,int val){
        nxt[++tot]=head[a];
        head[a]=tot;
        to[tot]=b;
        w[tot]=val;
    }
    inline int read(register int x=0,register char ch=getchar(),bool f=0){
        while(!isdigit(ch)) f=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return f?-x:x;
    }
    int main(){
        //freopen("b.in","r",stdin);
        int T=read();
        while(T--){
            n=read(); ans=0; tot=0;
            memset(head,0,sizeof(head));
            memset(v,0,sizeof(v));
            for(int i=1;i<=n;++i) d[i]=read();
            for(int i=1,a,b,val;i<n;++i){
                a=read(); b=read(); val=read();
                add(a,b,val); add(b,a,val);
            }
            findroot(1,1);
            solve(1);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    /*
    g++ bf.cpp -g
    ./a.out
    
    */
    View Code
    Informatik verbindet dich und mich. 信息将你我连结。
  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/seamtn/p/11496158.html
Copyright © 2011-2022 走看看