zoukankan      html  css  js  c++  java
  • BZOJ4860 Beijing2017树的难题(点分治+单调队列)

      考虑点分治。对子树按照根部颜色排序,每次处理一种颜色的子树,对同色和不同色两种情况分别做一遍即可,单调队列优化。但是注意到这里每次使用单调队列的复杂度是O(之前的子树最大深度+该子树深度),一不小心就退化成O(n2)。于是我们按照同颜色最大深度为第一关键字、子树深度为第二关键字排序,每次处理完一种颜色再与之前的其他颜色合并,这样每次的复杂度就是其自身深度了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define N 200010
    #define inf 2100000000
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,l,r,p[N],a[N],mxdeep[N],colordeep[N],deep[N],size[N],len[N],f[N],g[N],q[N][2],Q[N],t,ans=-inf;
    bool flag[N];
    struct data{int to,nxt,color;
    }edge[N<<1];
    struct data2
    {
        int x,y;
        bool operator <(const data2&a) const
        {
            return colordeep[y]<colordeep[a.y]||colordeep[y]==colordeep[a.y]&&y<a.y||colordeep[y]==colordeep[a.y]&&y==a.y&&mxdeep[x]<mxdeep[a.x];
        }
    }v[N];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].color=z,p[x]=t;}
    void make(int k,int from)
    {
        size[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from&&!flag[edge[i].to])
        {
            deep[edge[i].to]=deep[k]+1;
            make(edge[i].to,k);
            size[k]+=size[edge[i].to];
        }
    }
    int findroot(int k,int s)
    {
        int mx=0;
        for (int i=p[k];i;i=edge[i].nxt) 
        if (size[edge[i].to]<size[k]&&size[edge[i].to]>size[mx]&&!flag[edge[i].to]) mx=edge[i].to;
        if ((size[mx]<<1)>s) return findroot(mx,s);
        else return k;
    }
    void findmx(int k,int from,int root)
    {
        mxdeep[root]=max(mxdeep[root],deep[k]);
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from&&!flag[edge[i].to]) findmx(edge[i].to,k,root);
    }
    inline void ins(int k,int &head,int &tail,int *f){while (head<=tail&&f[Q[tail]]<f[k]) tail--;Q[++tail]=k;}
    inline void pop(int k,int &head,int &tail){while (head<=tail&&Q[head]>k) head++;}
    void bfs(int k,int last,int v,int d)
    {
        int head=0,tail=1;q[1][0]=k,q[1][1]=last;
        int h=1,t=0;for (int i=min(d,r);i>=l;i--) ins(i,h,t,g);
        do
        {
            int x=q[++head][0];if (deep[x]>=l&&deep[x]<=r) ans=max(ans,len[x]);
            if (deep[x]>deep[q[head-1][0]])
            {
                pop(r-deep[x],h,t);
                if (l-deep[x]>=0&&l-deep[x]<=d) ins(l-deep[x],h,t,g);
            }
            if (h<=t) ans=max(ans,len[x]+g[Q[h]]+v);
            for (int i=p[x];i;i=edge[i].nxt)
            if (deep[edge[i].to]>deep[x]&&!flag[edge[i].to])
            {
                len[edge[i].to]=len[x];
                if (edge[i].color!=q[head][1]) len[edge[i].to]+=a[edge[i].color];
                q[++tail][0]=edge[i].to,q[tail][1]=edge[i].color;
            }
        }while (head<tail);
    }
    void update(int k,int from)
    {
        g[deep[k]]=max(g[deep[k]],len[k]);
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from&&!flag[edge[i].to]) update(edge[i].to,k);
    }
    void solve(int k)
    {
        make(k,k);k=findroot(k,size[k]);
        flag[k]=1;deep[k]=0;make(k,k);
        int cnt=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (!flag[edge[i].to])
        {
            colordeep[edge[i].color]=mxdeep[edge[i].to]=0,findmx(edge[i].to,edge[i].to,edge[i].to);
            cnt++,v[cnt].x=edge[i].to,v[cnt].y=edge[i].color;
        }
        for (int i=p[k];i;i=edge[i].nxt)
        if (!flag[edge[i].to]) colordeep[edge[i].color]=max(colordeep[edge[i].color],mxdeep[edge[i].to]);
        sort(v+1,v+cnt+1);
        for (int i=1;i<=cnt;i++)
        {
            int t=i-1,d=0;
            while (t<cnt&&v[t+1].y==v[i].y)
            {
                len[v[++t].x]=a[v[i].y];
                bfs(v[t].x,v[t].y,-a[v[i].y],d);
                update(v[t].x,v[t].x);d=mxdeep[v[t].x];
            }
            int H=1,T=0;for (int j=min(colordeep[v[i-1].y],r);j>=l;j--) ins(j,H,T,f);
            for (int j=1;j<=d;j++)
            {
                pop(r-j,H,T);
                if (l>=j&&l-j<=d) ins(l-j,H,T,f);
                if (H<=T) ans=max(ans,g[j]+f[Q[H]]);
            }
            for (int j=0;j<=d;j++) f[j]=max(f[j],g[j]),g[j]=-inf;
            i=t;
        }
        for (int i=0;i<=mxdeep[v[cnt].x];i++) f[i]=-inf;
        for (int i=p[k];i;i=edge[i].nxt)
        if (!flag[edge[i].to]) solve(edge[i].to);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4860.in","r",stdin);
        freopen("bzoj4860.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),l=read(),r=read();
        for (int i=0;i<=n;i++) f[i]=g[i]=-inf;
        for (int i=1;i<=m;i++) a[i]=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            addedge(x,y,z),addedge(y,x,z);
        }
        solve(1);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    Android studio 几个坑,值得注意下。
    Android studio使用技巧,不定期更新。
    Android生猛上手,先写个拨号器。
    Ubuntu11.10安装教程,非虚拟机
    在线编辑器CKEditor,多图上传功能实现
    sql 中的NULL小问题 ,大bug
    工资低的.Net程序员,活该你工资低
    30岁的老龄程序员 ,不学习就会被淘汰
    计算商品税额和商品价格保留小数的时候的坑
    大话设计模式--简单工厂模式
  • 原文地址:https://www.cnblogs.com/Gloid/p/10004006.html
Copyright © 2011-2022 走看看