• [BZOJ2117]Crash的旅游计划


    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),N<=100000
    第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
    //样例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
     
    二分答案,然后点分树上二分$vector$判定
    代码:
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<vector>
      5 #include<algorithm>
      6 #define M 100010
      7 using namespace std;
      8 int n,m,num,S,root,k;
      9 int deep[M],f[M],fa[M],sz[M],size[M];
     10 int head[M],dis[M],son[M],maxn[M],top[M];
     11 bool vis[M];
     12 struct point{int to,next,dis;}e[M<<1];
     13 vector<int>S1[M],S2[M];
     14 void add(int from,int to,int dis) {
     15     e[++num].next=head[from];
     16     e[num].to=to;
     17     e[num].dis=dis;
     18     head[from]=num;
     19 }
     20 void dfs1(int x) {
     21     deep[x]=deep[f[x]]+1,sz[x]=1;
     22     for(int i=head[x];i;i=e[i].next) {
     23         int to=e[i].to;
     24         if(to==f[x]) continue;
     25         f[to]=x,dis[to]=dis[x]+e[i].dis;
     26         dfs1(to),sz[x]+=sz[to];
     27         if(sz[son[x]]<sz[to]) son[x]=to;
     28     }
     29 }
     30 void dfs2(int x,int tp) {
     31     top[x]=tp;
     32     if(son[x]) dfs2(son[x],tp);
     33     for(int i=head[x];i;i=e[i].next)
     34         if(e[i].to!=f[x]&&e[i].to!=son[x])
     35             dfs2(e[i].to,e[i].to);
     36 }
     37 int lca(int x,int y) {
     38     while(top[x]!=top[y]) {
     39         if(deep[top[x]]<deep[top[y]]) swap(x,y);
     40         x=f[top[x]];
     41     }
     42     return deep[x]<deep[y]?x:y;
     43 }
     44 int getdis(int x,int y) {
     45     return dis[x]+dis[y]-2*dis[lca(x,y)];
     46 }
     47 void getroot(int x,int fa) {
     48     size[x]=1;maxn[x]=0;
     49     for(int i=head[x];i;i=e[i].next) {
     50         int to=e[i].to;
     51         if(fa==to||vis[to]) continue;
     52         getroot(to,x);size[x]+=size[to];
     53         maxn[x]=max(maxn[x],size[to]);
     54     }
     55     maxn[x]=max(maxn[x],S-size[x]);
     56     if(maxn[x]<maxn[root]) root=x;
     57 }
     58 void solve(int x,int ff) {
     59     fa[x]=ff;vis[x]=true;
     60     for(int i=head[x];i;i=e[i].next) {
     61         int to=e[i].to;
     62         if(vis[to]) continue;
     63         S=size[to],root=0,getroot(to,x);
     64         solve(root,x);
     65     }
     66 }
     67 void update(int x) {
     68     S1[x].push_back(0);
     69     for(int i=x;fa[i];i=fa[i]) {
     70         int dt=getdis(x,fa[i]);
     71         S1[fa[i]].push_back(dt);
     72         S2[i].push_back(dt);
     73     }
     74 }
     75 int get1(int id,int d) {
     76     int l=0,r=S1[id].size()-1,ans=0;
     77     while(l<=r) {
     78         int mid=(l+r)/2;
     79         if(S1[id][mid]<=d) l=mid+1,ans=mid+1;
     80         else r=mid-1;
     81     }
     82     return ans;
     83 }
     84 int get2(int id,int d) {
     85     int l=0,r=S2[id].size()-1,ans=0;
     86     while(l<=r) {
     87         int mid=(l+r)/2;
     88         if(S2[id][mid]<=d) l=mid+1,ans=mid+1;
     89         else r=mid-1;
     90     }
     91     return ans;
     92 }
     93 int query(int x,int d) {
     94     int ans=get1(x,d);
     95     for(int i=x;fa[i];i=fa[i]) {
     96         int dt=getdis(fa[i],x);
     97         if(dt>d) continue;
     98         ans+=get1(fa[i],d-dt);
     99         ans-=get2(i,d-dt);
    100     }
    101     return ans;
    102 }
    103 int main() {
    104     char s[10];scanf("%s",s);
    105     scanf("%d%d",&n,&k);k++;
    106     for(int i=1;i<n;i++) {
    107         int a,b,c;scanf("%d%d%d",&a,&b,&c);
    108         add(a,b,c),add(b,a,c);
    109     }
    110     dfs1(1),dfs2(1,1);
    111     maxn[0]=S=n,getroot(1,0),solve(root,0);
    112     for(int i=1;i<=n;i++) 
    113         update(i);
    114     for(int i=1;i<=n;i++) {
    115         if(!S1[i].empty()) sort(S1[i].begin(),S1[i].end());
    116         if(!S2[i].empty()) sort(S2[i].begin(),S2[i].end());
    117     }
    118     for(int i=1;i<=n;i++) {
    119         int l=0,r=1e9,ans=1e9;
    120         while(l<=r) {
    121             int mid=(l+r)/2;
    122             if(query(i,mid)>=k) ans=mid,r=mid-1;
    123             else l=mid+1;
    124         }
    125         printf("%d
    ",ans);
    126     }
    127     return 0;
    128 }
  • 相关阅读:
    windows平台部署.netcore和vue项目
    .netcore系统权限认证
    全文检索 识别pdf 图片OCR识别
    搜索引擎solr的安装与配置
    SQLSugar动态拼接Lambda表达式(顺便提一个sqlsugar框架的bug)
    .netcore项目部署linux
    vue+element 部署linux服务器
    使用七牛云存储上传文件学习案例
    MSSQL 全库搜索 指定字符串
    系统右键自定义功能-右键备份【C#】
  • 原文地址:https://www.cnblogs.com/Slrslr/p/10058889.html
Copyright © 2020-2023  润新知