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

bzoj-2051 A Problem For Fun

时间:2015-11-26 15:22:22      阅读:428      评论:0      收藏:0      [点我收藏+]

标签:

题意:

给出一棵n个结点的树,边上有权值;

对于每个点求离它第k小的距离;

n<=50000;


题解:

正解似乎是树分治维护距离,然后二分答案啥的,时间复杂度O(nlog^3);

但是如果想不到树分治怎么办呢?那么就来写一个逗比做法吧!

考虑从一个点转移到另外一个点,这个转移过程对于一些点是增加这条边的权值,另一些是减少这条边的权值;

而投影到DFS序上,就是对于子树区间的加减修改;

从而将原题转化成区间修改+全局K小值的问题。。。

呵呵

于是我去膜了膜wyfcyx大爷,得到了一个污算法。。

反正不可做,那就分块吧(设每块的大小为B);

每个块内维护一个有序序列,查询时二分答案,然后统计小于当前mid的有多少数;

那么初始化就是n/B*BlogB=nlogB,每次查询都是log(ans)*n/B*logB;

每次修改整块的修改打标记,非整块的暴力修改,然后利用归并排序将序列重新排成有序;

这样每一次的修改就是n/B+B;

所以我们令B=√n*logn,时间复杂度为O(n*(log(ans)*√n+√n/logn+√n*logn)),大概就是O(n√nlogn)的啦。。。;

讲道理,我们这个√n比log^2n还是小一点的呢。。

然而实际上隐藏了一些常数。。不过对于极限数据,5s以内还是可以出解的;

bzoj 4317: Atm的树 双倍经验;


代码:


#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 51000
#define M 500000000
#define MEM 1000000
#define lson l,mid,no<<1
#define rson mid+1,r,no<<1|1
using namespace std;
int next[N],to[N],val[N],head[N],ce;
int L[N],R[N],tot;
int n,k,B,cnt,ans[N];
int dis[N],cov[N];
struct node
{
    int* t;
    int no;
    friend bool operator <(node a,node b)
    {
        return *a.t+cov[a.no]<*b.t+cov[b.no];
    }
}p[N];
void add(int x,int y,int v)
{
    to[++ce]=y;
    next[ce]=head[x];
    val[ce]=v;
    head[x]=ce;
}
void dfs(int x,int d)
{
    L[x]=++tot;
    dis[L[x]]=d;
    for(int i=head[x];i;i=next[i])
        dfs(to[i],d+val[i]);
    R[x]=tot;
}
 
void Build(int x)
{
    int i,l=max(x*B,1),r=min((x+1)*B,n+1);
    for(i=l;i<r;i++)
        p[i].t=&dis[i],p[i].no=x;
    sort(p+l,p+r);
}
int calc(node t)
{
    int i,ret=0,l,r;
    for(i=0;i<=cnt;i++)
    {
        l=max(i*B,1),r=min((i+1)*B,n+1);
        ret+=lower_bound(p+l,p+r,t)-p-l;
    }
    return ret;
}
int query()
{
    int l,r,mid;
    node t;
    t.t=&mid,t.no=cnt+1;
    l=0,r=M;
    while(l<=r)
    {
        mid=l+r>>1;
        if(calc(t)+1<=k)
            l=mid+1;
        else
            r=mid-1;
    }
    return r;
}
void update(int l,int r,int v)
{
    static node st[N][2];
    int i,j,k,tl,tr,top[2];
    for(i=0;i<l/B;i++)
        cov[i]+=v;
    for(i++;i<r/B;i++)
        cov[i]-=v;
    for(i=r/B+1;i<=cnt;i++)
        cov[i]+=v;
    if(l/B!=r/B)
    {
        tl=max(l/B*B,1),tr=min((l/B+1)*B,n+1);
        for(i=tl;i<tr;i++)
        {
            if(i<l)
                dis[i]+=v;
            else
                dis[i]-=v;
        }
        top[0]=top[1]=0;
        for(i=tl;i<tr;i++)
        {
            if(p[i].t>=&dis[l])
                st[++top[0]][0]=p[i];
            else
                st[++top[1]][1]=p[i];
        }
        for(i=tl,j=1,k=1;i<tr;i++)
        {
            if(j<=top[0]&&k<=top[1])
                p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1];
            else
                p[i]=j<=top[0]?st[j++][0]:st[k++][1];
        }
        tl=max(r/B*B,1),tr=min((r/B+1)*B,n+1);
        for(i=tl;i<tr;i++)
        {
            if(i<=r)
                dis[i]-=v;
            else
                dis[i]+=v;
        }
        top[0]=top[1]=0;
        for(i=tl;i<tr;i++)
        {
            if(p[i].t<=&dis[r])
                st[++top[0]][0]=p[i];
            else
                st[++top[1]][1]=p[i];
        }
        for(i=tl,j=1,k=1;i<tr;i++)
        {
            if(j<=top[0]&&k<=top[1])
                p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1];
            else
                p[i]=j<=top[0]?st[j++][0]:st[k++][1];
        }
    }
    else
    {
        tl=max(l/B*B,1),tr=min((l/B+1)*B,n+1);
        for(i=tl;i<tr;i++)
        {
            if(i<l||i>r)
                dis[i]+=v;
            else
                dis[i]-=v;
        }
        top[0]=top[1]=0;
        for(i=tl;i<tr;i++)
        {
            if(p[i].t<&dis[l]||p[i].t>&dis[r])
                st[++top[0]][0]=p[i];
            else
                st[++top[1]][1]=p[i];
        }
        for(i=tl,j=1,k=1;i<tr;i++)
        {
            if(j<=top[0]&&k<=top[1])
                p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1];
            else
                p[i]=j<=top[0]?st[j++][0]:st[k++][1];
        }
         
    }
}
void slove(int x)
{
    ans[x]=query();
    for(int i=head[x];i;i=next[i])
    {
        update(L[to[i]],R[to[i]],val[i]);
        slove(to[i]);
        update(L[to[i]],R[to[i]],-val[i]);
    }
}
int main()
{
    int i,x,y,v;
    scanf("%d%d",&n,&k);
    k++;
    B=(int)sqrt(n)*log2(n);
    cnt=n/B;
    for(i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&v);
        add(x,y,v);
    }
    dfs(1,0);
    for(i=0;i<=cnt;i++)
        Build(i);
    slove(1);
    for(i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}



bzoj-2051 A Problem For Fun

标签:

原文地址:http://blog.csdn.net/ww140142/article/details/50054389

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