码迷,mamicode.com
首页 > 其他好文 > 详细

CF1266F

时间:2020-06-13 21:06:31      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:中心   continue   包含   情况   void   离线   date   play   pop   

来一个O(nlogn)做法,跑得挺快。

技术图片

假设点集S包含点X,Y,Z,红色链长度为a,黄色链长度为b,绿色链长度为c。

如果|a-b|>1,那么有|dis(X,Z)-dis(Y,Z)|=|(a+c)-(b+c)|=|a-b|>1,不符合题目要求。

所以a=b或|a-b|=1。所以存在一个点A,到S中每一个点的距离都为p或p+1(0<2p<n)。

接着发现一定是一下两种情况之一(证明留给读者自行思考):

情况1:S中任两点到点A的链没有公共边。

情况2:S中任意一点P满足min(dis(P,A),dis(P,A‘))=p(A‘为一个与A相邻的点)。

于是,S中的点便是由A点或者A点及A‘点伸出来的若干条“长度相近”链的另一端点组成(如图)。

技术图片

其中“长度相近”指长度均为p或p+1,且长度为p的链只有一条或长度为p+1的链只有一条。

预处理出每一个点连出所有边引出链的最大长度,对于一个点P,设其引出第k长的链长度为len(p,k),则$ans_{len(p,k)} \geq k$。

又因为$ans_x \geq ans_{x+2}$,所以可以先对于每个k,求出最大的x使$ans_x \geq k$,再做一边后缀最大值。

先枚举其中一个中心点,再枚举其引出的一条边,设k为这条边引出链的最大长度,一共可以引出d条长度为k的链。

那么执行ans[k]=max(ans[k],d)。对每个点,将其引出链按最大长度排序即可求得d和k。

这样一个中心点的情况就搞定了。

对于点i,设集合S_i中有deg_i个元素,分别为i引出deg_i条边所引出链长度的最大值。

枚举其中一个中心点P,设另一个为Q,则P,Q相邻。我们只需要对于每一个$S_{P,j}(0 \leq j<deg_P)$,找到点Q,使集合S_P,S_Q中大于$S_{P,j}$的数最多。因为每个数相当于一条链的长度。把问题离线下来(按照$S_{P,j}$从大到小排序),用bfs序把与P相邻的点转化为一段区间以及fa_P,然后写一个支持单点加,区间最大值的线段树即可。具体见代码吧。

技术图片
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,cnt=-1,temp,qcnt=0;
int deg[500000],l1[500000],l2[500000];
int fir[500000],to[1000000],nxt[1000000];
int fa[500000],ans[500000],f[500000];
int id[500000],mx[2000000],o[500000];
vector<int> len[500000];
struct query{
    int x,val,o;
}qu[1000000];
inline bool comp(query q1,query q2)
{
    return q1.val>q2.val;
}
inline void Add(int a,int b,int c)
{
    qu[qcnt].x=a;
    qu[qcnt].val=c;
    qu[qcnt++].o=b;
    return;
}
inline void add(int a,int b)
{
    to[++cnt]=b;
    nxt[cnt]=fir[a];
    fir[a]=cnt;
    deg[b]++;
    return;
}

void dfs1(int i,int f)
{
    fa[i]=f;
    for(int j=fir[i];j!=-1;j=nxt[j]){
        if(to[j]==f)
            continue;
        dfs1(to[j],i);
        l1[i]=max(l1[i],l1[to[j]]);
    }
    l1[i]++;
    return;
}
void dfs2(int i,int l)
{
    l2[i]=l;
    int mx1=0,mx2=0;
    for(int j=fir[i];j!=-1;j=nxt[j]){
        temp=to[j];
        if(temp==fa[i])
            continue;
        if(mx1<l1[temp]){
            mx2=mx1; mx1=l1[temp];
        }
        else if(mx2<l1[temp])
            mx2=l1[temp];
    }
    for(int j=fir[i];j!=-1;j=nxt[j]){
        temp=to[j];
        if(temp==fa[i])
            continue;
        if(mx1==l1[temp])
            dfs2(temp,max(mx2,l2[i])+1);
        else dfs2(temp,max(mx1,l2[i])+1);
    }
    return;
}

int t1,t2;
void upd(int i,int l,int r)
{
    if(l==r){
        mx[i]++;
        return;
    }
    int mid=(l+r)>>1;
    if(t1<=mid) upd(i<<1,l,mid);
    else upd(i<<1|1,mid+1,r);
    mx[i]=max(mx[i<<1],mx[i<<1|1]);
    return;
}
inline void update(int x)
{
    t1=x; upd(1,0,n-1); f[x]++;
    return;
}
int qry(int i,int l,int r)
{
    if(t1<=l&&r<=t2)
        return mx[i];
    int mid=(l+r)>>1,res=0;
    if(t1<=mid) res=qry(i<<1,l,mid);
    if(mid<t2) res=max(res,qry(i<<1|1,mid+1,r));
    return res;
}
inline int querymax(int x,int y)
{
    t1=x; t2=y;
    return qry(1,0,n-1);
}

void bfs(void)
{
    cnt=0;
    id[0]=cnt++;
    queue<int> q;
    q.push(0);
    while(q.size()>0){
        int i=q.front();
        q.pop();
        o[i]=cnt-1;
        for(int j=fir[i];j!=-1;j=nxt[j])
            if(to[j]!=fa[i]){
                id[to[j]]=cnt++;
                q.push(to[j]);
            }
    }
    return;
}
void solve(void)
{
    for(int i=2;i<n;i++)
        ans[i]=1;
    for(int i=0;i<n;i++){
        int s=deg[i];
        for(int d=1;d<=s;d++){
            temp=len[i][s-d]*2;
            if(temp<n) ans[temp]=max(ans[temp],d);
            if(temp<=n) ans[temp-1]=max(ans[temp-1],d);
            if(temp+1<n&&d>1&&len[i][s-d+1]>len[i][s-d])
                ans[temp+1]=max(ans[temp+1],d);
        }
    }
    
    for(int i=0;i<n;i++)
        for(int d=1;d<=deg[i];d++)
            Add(i,d,len[i][deg[i]-d]);
    sort(qu,qu+qcnt,comp);
    int pos=0;
    for(int i=0;i<qcnt;i++){
        while(pos<qcnt&&qu[pos].val>=qu[i].val)
            update(id[qu[pos++].x]);
        int X=qu[i].x,D=2*qu[i].val;
        temp=querymax(o[X]+1,o[X]+deg[X]-1);
        if(X!=0) temp=max(temp,f[id[fa[X]]]);
        ans[D]=max(ans[D],temp+qu[i].o-2);
    }
    return;
}

int main(void)
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        fir[i]=-1;
    int a,b;
    for(int i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        add(a-1,b-1); add(b-1,a-1);
    }
    dfs1(0,-1); dfs2(0,0); bfs();
    for(int i=1;i<n;i++){
        len[fa[i]].push_back(l1[i]);
        len[i].push_back(l2[i]);
    }
    for(int i=0;i<n;i++){
        sort(len[i].begin(),len[i].end());
        ans[1]=max(ans[1],deg[i]+1);
    }
    solve();
    for(int i=n-3;i>0;i--)
        ans[i]=max(ans[i],ans[i+2]);
    for(int i=1;i<n;i++)
        printf("%d ",ans[i]);
    printf("1\n");
    return 0;
}
View Code

 

CF1266F

标签:中心   continue   包含   情况   void   离线   date   play   pop   

原文地址:https://www.cnblogs.com/2005lz/p/13121667.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!