zoukankan      html  css  js  c++  java
  • poj3162 Walking Race

    题目大意:给一个树形图n个点(n-1条边),XXX要练习竞走,每次选定一个点k作为开始点,每次走从k开始能走的最长的一条路径(不要重边)。要求出最长的连续的这样的k,假设连续有kx个,前提:这样kx条路径的长度的任意两个值的差不超过m。

    输入: n,m; 接下来n-1行数据,每一行两个整数fi,di。第i行表示 第i+1个点与fi连着一条长度为di的边。

    不用想,稍微有一点点水平的朋友都能想到,首先对于每一个点,用一个树形dp求每个点能走到的最长路径长。

    树形dp

      定义结构体: max1,max1from, max2。 //记录跟这个点有关的 最长路径长、最长路径长点, 第二最长路径长.

      tree_dp1求出只走子树的边能到达的 max1,max1from, max2,max2from。

      tree_dp2补上求出加上走向父节点的边能到达的 max1,max1from, max2。

    第一步还是挺简单的,相信大多数人YY一下就可以搞定的。这样从每个点开始能走到的最长路径长maxlen就出来了。这个效率是O(n)的

    然后需要做的是: 求出一个最长的连续区间,对这样区间上任意两个点i,j有 |maxlen[i] - maxlen[j]| <= m。

    单调队列

      /**************************************************/

      大家仔细看看这些星号就知道了。

      (O(∩_∩)O~跟你开玩笑的,还是看163到179行的代码吧)

    当然第二步也是很简单的,只是要写个水水的线段树作辅助。。。。这个效率最坏O(n)*log(n)+O(n)。

    PS:个人觉得这第二步可以试试枚举起点,然后二分搜索区间终点,由于线段树查询效率为log(n),所以总效率O(n)*log(n)*log(n),再加上一些剪枝可以卡过的,可是……

    没有可是了,擦擦,贡献了n个WA。

    献上代码,与大家共勉!

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <stack>
      7 using namespace std;
      8 const int maxn = 1000100;
      9 const int maxe = maxn*2;
     10 const int maxf = (1<<31)^(-1);
     11 
     12 struct edge{
     13        int u,v,c;
     14        edge(int a=0,int b=0,int d=0){ u=a, v=b, c=d; }
     15 }e[maxe];
     16 int head[maxn];
     17 int next[maxe];
     18 int cnt;
     19 void add(int u,int v,int c){
     20      e[cnt] = edge(u,v,c);
     21      next[cnt] = head[u], head[u] = cnt++;
     22 }
     23 struct node{
     24     int p, plen;
     25     int max1,max1from;
     26     int max2,max2from;
     27 }no[maxn];
     28 stack<int> iden;
     29 int visited[maxn];
     30 void tree_dp1(int root){
     31     memset(visited,0,sizeof(visited));
     32     while(!iden.empty()) iden.pop();
     33     iden.push(root);
     34     int u,v=root;
     35     no[root].p = 0, no[root].plen=0;
     36     no[v].max1 = no[v].max2 = 0;
     37     no[v].max1from = no[v].max2from = -1;
     38     while(!iden.empty()){
     39         u = iden.top();
     40         if(!visited[u]){
     41             for(int i=head[u];i>=0;i=next[i]){
     42                 v = e[i].v;
     43                 if(v == no[u].p) continue;
     44                 no[v].p = u; no[v].plen = e[i].c;
     45                 no[v].max1 = no[v].max2 = 0;
     46                 no[v].max1from = no[v].max2from = -1;
     47                 iden.push(v);
     48             }
     49         }
     50         else{ //当前点u访问完毕
     51             iden.pop();
     52             for(int i=head[u];i>=0;i=next[i]){
     53                 v = e[i].v;
     54                 if(v == no[u].p) continue;
     55                 int len = e[i].c + no[v].max1;
     56                 if(len > no[u].max1){
     57                     no[u].max2 = no[u].max1, no[u].max2from = no[u].max1from;
     58                     no[u].max1 = len; no[u].max1from = v;
     59                 }
     60                 else {
     61                     if(len > no[u].max2)
     62                         no[u].max2 = len, no[u].max2from = v;
     63                 }
     64             }
     65         }
     66         visited[u] = 1;
     67     }
     68 }
     69 int maxlen[maxn];
     70 void tree_dp2(int root){
     71     while(!iden.empty()) iden.pop();
     72     iden.push(root);
     73     int u,v;
     74     while(!iden.empty()){
     75         u = iden.top(); iden.pop();
     76         for(int i=head[u];i>=0;i=next[i]){
     77             v = e[i].v;
     78             if(v == no[u].p) continue;
     79             iden.push(v);
     80         }
     81         maxlen[u] = no[u].max1;
     82         if(u != root){
     83             int p = no[u].p,len;
     84             if(no[p].max1from != u)
     85                 len = no[p].max1+no[u].plen;
     86             else
     87                 len = no[p].max2+no[u].plen;
     88             maxlen[u] = max(maxlen[u],len);
     89             if(len > no[u].max1){
     90                 no[u].max2 = no[u].max1, no[u].max2from = no[u].max1from;
     91                 no[u].max1 = len; no[u].max1from = p;
     92             }
     93             else {
     94                 if(len > no[u].max2)
     95                  no[u].max2 = len, no[u].max2from = p;
     96             }
     97         }
     98     }
     99 }
    100 void initial(){
    101     cnt = 0;
    102     memset(head,-1,sizeof(head));
    103 }
    104 struct segment{
    105     int left,right;
    106     int maxv,minv;
    107 }a[maxn*4];
    108 void build(int left,int right,int k){
    109     a[k].left=left, a[k].right=right;
    110     a[k].minv = a[k].maxv = maxlen[left];
    111     if(left < right){
    112         int mid=(left+right)>>1,k2=k<<1;
    113         build(left,mid,k2);
    114         build(++mid,right,k2+1);
    115         a[k].minv = min(a[k2].minv,a[k2+1].minv);
    116         a[k].maxv = max(a[k2].maxv,a[k2+1].maxv);
    117     }
    118 }
    119 int query_min(int l,int r,int k){
    120     if(l <= a[k].left && r >= a[k].right)
    121         return a[k].minv;
    122     int mid=(a[k].left+a[k].right)>>1,k2=k<<1;
    123     int k3=k2+1;
    124     if(r <= mid)
    125         return query_min(l,r,k2);
    126     else {
    127         if(l > mid)
    128             return query_min(l,r,k3);
    129         //else
    130             return min(query_min(l,mid,k2),query_min(mid+1,r,k3));
    131     }
    132 }
    133 int query_max(int l,int r,int k){
    134     if(l <= a[k].left && r >= a[k].right)
    135         return a[k].maxv;
    136     int mid=(a[k].left+a[k].right)>>1,k2=k<<1;
    137     int k3=k2+1;
    138     if(r <= mid)
    139         return query_max(l,r,k2);
    140     else {
    141         if(l > mid)
    142             return query_max(l,r,k3);
    143         //else
    144             return max(query_max(l,mid,k2),query_max(mid+1,r,k3));
    145     }
    146 }
    147 int main()
    148 {
    149     int n,m;
    150     while(scanf("%d%d",&n,&m) != EOF){
    151         initial();
    152         int fi,di;
    153         for(int i=1;i<n;i++)
    154             scanf("%d%d",&fi,&di), add(i+1,fi,di), add(fi,i+1,di);
    155         //if(m < 0){ printf("0
    ");  continue; }
    156         int root = 1;
    157         tree_dp1(root);
    158         //for(int i=1;i<=n;i++) printf("no[%d]: %d	%d,	 %d	%d
    ",i,no[i].max1,no[i].max1from,no[i].max2,no[i].max2from);
    159         tree_dp2(root);
    160         build(1,n,1);
    161         //for(int i=1;i<=n;i++) printf("no[%d]: %d	%d,	 %d	%d
    ",i,no[i].max1,no[i].max1from,no[i].max2,no[i].max2from);
    162         //for(int i=1;i<=n;i++) printf("maxlen[%d] = %d
    ",i,maxlen[i]);
    163         int ret = 1;
    164         int left=1,right=1;
    165         int tpmin=maxlen[1],tpmax=maxlen[1];
    166         while(left<=right && right<=n){
    167             if(tpmax-tpmin <= m){
    168                 ret = max(ret,right-left+1);
    169                 right++;
    170                 tpmin = min(tpmin,maxlen[right]);
    171                 tpmax = max(tpmax,maxlen[right]);
    172             }
    173             else {
    174                 left++;
    175                 tpmin = query_min(left,right,1);
    176                 tpmax = query_max(left,right,1);
    177             }
    178             if(ret > n - left) break;
    179         }
    180         printf("%d
    ",ret);
    181     }
    182     return 0;
    183 }
    View Code

     
      单调队列核心:最大值的单调队列保持递减,最小值得单调队列保持递增!然后记录队列中每个最值的下标,使用left、right游标追赶。下面来个个人珍藏版代码。

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <stack>
      7 using namespace std;
      8 const int maxn = 1000100;
      9 const int maxe = maxn*2;
     10 const int maxf = (1<<31)^(-1);
     11 
     12 struct edge{
     13        int u,v,c;
     14        edge(int a=0,int b=0,int d=0){ u=a, v=b, c=d; }
     15 }e[maxe];
     16 int head[maxn];
     17 int next[maxe];
     18 int cnt;
     19 void add(int u,int v,int c){
     20      e[cnt] = edge(u,v,c);
     21      next[cnt] = head[u], head[u] = cnt++;
     22 }
     23 void initial(){
     24     cnt = 0;
     25     memset(head,-1,sizeof(head));
     26 }
     27 
     28 struct node{
     29     int max1,max2; int max1from;
     30     int p,pd,sc;
     31 }no[maxn];
     32 int visited[maxn];
     33 void tree_dp1(int n,int root){
     34     for(int i=1;i<=n;i++) visited[i]=0;
     35     stack<int> st; st.push(root);
     36     int u,v,d;
     37     while(!st.empty()){
     38         u=st.top();
     39         //printf("u = %d, visited[u] = %d
    ",u,visited[u]);
     40         if(!visited[u]){
     41             for(int i=head[u];i>=0;i=next[i]){
     42                 v=e[i].v;
     43                 if(v == no[u].p) continue;
     44                 no[v].p=u, no[v].pd=e[i].c;
     45                 st.push(v);
     46             }
     47             visited[u]=1;
     48         }else {
     49             for(int i=head[u];i>=0;i=next[i]){
     50                 v=e[i].v;
     51                 if(v == no[u].p) continue;
     52                 d=e[i].c+no[v].max1;
     53                 if(d >= no[u].max1)
     54                     no[u].max2=no[u].max1, no[u].max1=d, no[u].max1from=v;
     55                 else if(d > no[u].max2)
     56                     no[u].max2=d;
     57             }
     58             st.pop();
     59         }
     60     }
     61 }
     62 void tree_dp2(int n,int root){
     63     for(int i=1;i<=n;i++) visited[i]=0;
     64     stack<int> st; st.push(root);
     65     int u,v,p,d;
     66     while(!st.empty()){
     67         u=st.top();
     68         //printf("u = %d, visited[u] = %d
    ",u,visited[u]);
     69         if(!visited[u]){
     70             for(int i=head[u];i>=0;i=next[i])
     71             if(e[i].v != no[u].p)
     72                 st.push(e[i].v);
     73             if(u != root){
     74                 p = no[u].p;
     75                 d = (no[p].max1from==u)?no[p].max2:no[p].max1;
     76                 d += no[u].pd;
     77                 if(d > no[u].max1)  no[u].max2=no[u].max1, no[u].max1=d, no[u].max1from=p;
     78                 else if(d > no[u].max2) no[u].max2=d;
     79             }
     80             visited[u]=1;
     81         }else
     82             st.pop();
     83     }
     84 }
     85 int maxlen[maxn];
     86 int dddl(int n,int M){
     87     if(n <= 0) return n;
     88     if(M < 0) return 0;
     89     deque<int> qmax,qmin; deque<int> idmax,idmin;
     90     int ans=0;
     91     int left=1,right=1;
     92     while(right <= n){
     93         while(!qmax.empty() && maxlen[right] >= qmax.back())
     94             qmax.pop_back(), idmax.pop_back();
     95         qmax.push_back(maxlen[right]); idmax.push_back(right);
     96 
     97         while(!qmin.empty() && maxlen[right] <= qmin.back())
     98             qmin.pop_back(), idmin.pop_back();
     99         qmin.push_back(maxlen[right]); idmin.push_back(right);
    100         while(qmax.front()-qmin.front() > M && left<right){
    101             left++;
    102             while(idmax.front() < left) idmax.pop_front(), qmax.pop_front();
    103             while(idmin.front() < left) idmin.pop_front(), qmin.pop_front();
    104         }
    105         ans = max(ans,right-left+1);
    106         right++;
    107     }
    108     return ans;
    109 }
    110 int main()
    111 {
    112     int n,m;
    113     while(scanf("%d%d",&n,&m) != EOF){
    114         initial();
    115         int fi,di;
    116         for(int i=1;i<n;i++)
    117             scanf("%d%d",&fi,&di), add(i+1,fi,di), add(fi,i+1,di);
    118         int root=1;
    119         tree_dp1(n,root);
    120         tree_dp2(n,root);
    121         for(int i=1;i<=n;i++)
    122             maxlen[i]=no[i].max1;
    123         printf("%d
    ",dddl(n,m));
    124     }
    125     return 0;
    126 }
    View Code
  • 相关阅读:
    JSP基本使用
    Web介绍
    通用的数据库数据操作类
    Java集合与泛型
    我是如何刷 LeetCode
    这或许是东半球讲十大排序算法最好的一篇文章(c++版程序)
    【游戏后端】游戏服务器端开发的一些建议(转载)
    【高并发】Redis为什么是单线程,高并发快的3大原因详解
    【高可用】Redis哨兵、复制、集群的设计原理与区别
    深入理解各种排序的一些思路及分享
  • 原文地址:https://www.cnblogs.com/karlvin/p/3225848.html
Copyright © 2011-2022 走看看