• 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. 信息将你我连结。
  • 相关阅读:
    MySQL RR隔离 读一致性
    C++奥赛一本通刷题记录(高精度)
    CodeVs天梯之Diamond
    CodeVs天梯之Gold
    CodeVs天梯之Silver
    CodeVs天梯之Bronze
    【2018.1.14】本蒟蒻又回来了
    test
    UVa12545
    UVa1149
  • 原文地址:https://www.cnblogs.com/seamtn/p/11496158.html
Copyright © 2020-2023  润新知