bzoj-2051 A Problem For Fun

来源:互联网 发布:微信回调域名 编辑:程序博客网 时间:2024/06/06 06:52

题意:

给出一棵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|1using 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;}



0 0
原创粉丝点击