BZOJ2117

2117: [2010国家集训队]Crash的旅游计划

Time Limit: 150 Sec   Memory Limit: 552 MB
Submit: 179   Solved: 43
[ Submit][ Status][ Discuss]

Description

眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游。 Crash和陶陶所要去的城市里有N (N > 1) 个景点,Crash用正整数1到N给景点标号。这些景点之间通过N − 1条无向道路相连,每条道路有一个长度,并且保证任意两个景点之间都有且仅有一条路径相连。现在对于一个景点s,Crash和陶陶从s出发,然后访问一个景点序列{v0, v1, v2, … , vk},其中v0就是s,且vi-1和vi(0 < i ≤ k)之间有道路相连。需要注意的是,陶陶和Crash访问的景点序列中不会只有景点s。为了使旅程不显得乏味,在一个景点序列里他们不会重复走某条道路。我们定义这个序列的旅游代价为经过道路的长度和。下面问题出现了:陶陶:我们走一条景点数最多的景点序列吧。 Crash:倒,你想把我累死啊。陶陶:谁叫你整天坐在电脑前面,不出来锻炼,这下子傻了吧,哈哈哈哈~~ Crash:不行,如果你非要走景点数最多的我就不陪你走了。陶陶:笑喷油你很跳嘛! Crash:这样吧,我们来写伸展树,如果我写的比你快,你就要听我的。陶陶:这样不公平哎,我们来玩PES吧,当然你要让我选法国队,如果你输了你就要听我的。 Crash:倒,你这是欺负我,T_T~ 陶陶:笑喷油好说话哎。 Crash:囧…… …… 这样搞了半天,最终陶陶和Crash用很多次包剪锤决定出选择旅游代价第K小 的景点序列。不过呢Crash和陶陶还没确定开始旅行的景点s,因此他希望你对于每个景点i,计算从景点i开始的景点序列中旅游代价第K小的值。

Input

共N行。第1行包含一个字符和两个正整数,字符为ABCD中的一个,用来表示这个测试数据的类型(详见下面的数据规模和约定),另外两个正整数分别表示N和K (K < N)。第2行至第N行,每行有三个正整数u、v和w (u, v ≤ N,w ≤ 10000)。表示u号景点和v号景点之间有一条道路,长度为w。输入文件保证符合题目的约定,即任意两个景点之间都有且仅有一条路径相连。

Output

共N行,每行有一个正整数。第i行的正整数表示从i号景点开始的景点序列中旅游代价第K小的代价。

Sample Input

A 6 3
1 2 2
1 3 4
1 4 3
3 5 1
3 6 2

Sample Output

4
6
4
7
5
6

HINT

样例1中输出对应的景点序列分别为:1号景点是{1, 3},2号景点是{2, 1, 3},3号景点是{3, 1},4号景点是{4, 1, 3},5号景点是{5, 3, 1},6号景点是{6, 3, 1}。 保证每个景点到1号景点需要经过的道路数不超过30。 N ≤100000


本题点分治(好像是废话)

点分到一个子树时就算一下根的答案

每次算的时候二分答案,然后check时用一些东西维护由根向上的递归树(logn层)

如下,假设要算黄点的答案,现在到了绿点,就加上绿点整棵子树的答案减去从绿点再到黄点的答案...**&^*&^*%*

好像我用了map还用了树剖求LCA


#pragma GCC optimize(3)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100111
using namespace std;
typedef long long ll;
struct edge{
    int r,nxt,w;
}e[maxn<<1];
char _[2];
vector<pair<int,int> >id[maxn];
vector<ll> vec[maxn*2];
vector<ll> v[maxn];
int dep[maxn],head[maxn],size[maxn],top[maxn],son[maxn],esz,idsz;
int fa[maxn],num,rt,n,k,f[maxn];
bool vis[maxn];
ll anses[maxn],mn,dist[maxn],rbd;
void getsize(int u,int f){
    num++;
    for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f&&!vis[e[t].r])
        getsize(e[t].r,u);
}
void findroot(int u,int f){
    size[u]=1;
    int mx=0;
    for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f&&!vis[e[t].r])
        findroot(e[t].r,u),size[u]+=size[e[t].r],mx=max(mx,size[e[t].r]);
    mx=max(mx,num-size[u]);
    if(mx<mn)mn=mx,rt=u;
}
int dfs1(int u,int f,ll d,int p){
    ::f[u]=f,dist[u]=d,dep[u]=p;
    int mxsize=0,size=1;
    for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f){
        int s=dfs1(e[t].r,u,d+e[t].w,p+1);
        if(s>mxsize)mxsize=s,son[u]=e[t].r;
        size+=s;
    }
    return size;
}
void dfs2(int u,int tp){
    top[u]=tp;
    if(son[u])dfs2(son[u],tp);
    for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f[u]&&e[t].r!=son[u])
        dfs2(e[t].r,e[t].r);
}
void getdist(vector<ll>& p,int u,int f,ll dist){
//  printf("{{%lld}}",dist);
    p.push_back(dist);
    for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f&&!vis[e[t].r])
        getdist(p,e[t].r,u,dist+e[t].w);
}
ll get(const vector<ll>&v,ll ans){
    if(v.empty())return 0;
    int l=0,r=v.size()-1;
    while(l<r){
        int mid=(l+r+1)/2;
        if(v[mid]>=ans)r=mid-1;
        else l=mid;
    }
    return v[l]<ans?l+1:0;
}
int getid(int rt,int u){
    return lower_bound(id[rt].begin(),id[rt].end(),make_pair<int,int>(u,0))->second;
}
int lca(int u,int v){
    int tp1=top[u],tp2=top[v];
    while(tp1!=tp2){
        if(dep[tp1]<dep[tp2])swap(tp1,tp2),swap(u,v);
        u=f[tp1],tp1=top[u];
    }
    return dep[u]>dep[v]?v:u;
}
int getnear(int u,int v){
    int tp1=top[u],tp2=top[v],lst=u;
    while(tp1!=tp2) lst=tp1,u=f[tp1],tp1=top[u];
    if(u==v)return lst;
    else return son[v];
}
ll check(int u,ll ans){
    ll sum=0;
    int x=u,near;
    while(fa[x]){
        int lc=lca(u,fa[x]);
        ll dist1=(dist[u]+dist[fa[x]]-2*dist[lc]);
        ll dist2=(lc==fa[x]?dist[near=getnear(u,lc)]-dist[lc]:dist[fa[x]]-dist[near=f[fa[x]]]);
//      printf("{{%d,%d,%d,%d}}\n",u,fa[x],near,id[near]);
        sum+=get(v[fa[x]],ans-dist1)-get(vec[getid(fa[x],near)],ans-dist1-dist2);
        x=fa[x];
    }
    return sum;
}
void work(int u,int f){
    mn=1ll<<40,num=0;
    getsize(u,0);
    findroot(u,0);
    int rt=::rt;
    vis[rt]=true;
    fa[rt]=f;
//  printf("[%d,%d]\n",u,rt);
    for(int t=head[rt];t;t=e[t].nxt)if(!vis[e[t].r]){
//      if(id[e[t].r])exit(4324);
        vector<ll>& a=vec[id[rt].push_back(make_pair(e[t].r,++idsz)),idsz];
        getdist(a,e[t].r,rt,0);
        sort(a.begin(),a.end());
        for(int i=0;i<a.size();++i)
            v[rt].push_back(a[i]+e[t].w);
    }
    sort(id[rt].begin(),id[rt].end());
    v[rt].push_back(0);
    sort(v[rt].begin(),v[rt].end());
    ll l=0,r=rbd;
    while(l<r){
        ll mid=(l+r+1)/2;
//      printf("[ok]\n");
        ll ans=check(rt,mid)+get(v[rt],mid);
        if(ans>k)r=mid-1;
        else l=mid;
    }
    anses[rt]=l;
    for(int t=head[rt];t;t=e[t].nxt)if(!vis[e[t].r])
        work(e[t].r,rt);
}
void addedge(int u,int v,int w){
    e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;e[esz].w=w;
}
int main(){
//  freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);
    scanf("%s%d%d",_,&n,&k);
    for(int i=1,u,v,w;i<n;++i){
        scanf("%d%d%d",&u,&v,&w);rbd+=w;
        addedge(u,v,w),addedge(v,u,w);
    }
    dfs1(1,0,0,0),dfs2(1,1);
    work(1,0);
    for(int i=1;i<=n;++i)printf("%lld\n",anses[i]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值