您的位置:首页 > 其它

bzoj-2051 A Problem For Fun

2015-11-26 12:56 330 查看
题意:

给出一棵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
,to
,val
,head
,ce;
int L
,R
,tot;
int n,k,B,cnt,ans
;
int dis
,cov
;
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
;
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
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息