NOIP 2016 提高组 Day1 天天爱跑步

将树反向存储。从终点向起点反向搜索,。结果发现程序死循环。 从样例2得知: 还有可能向父亲节点走。

调整思路: 宽度搜索求最大路径,。

网上说:LCA。感觉有道理。如果用宽度搜索,这棵树就与无向图无异了。 

还没有通过。 明天继续

#include <bits/stdc++.h>
#define  debug
using namespace std;
const  int MM=300000;
int n,m;  //n:节点数  也是观察员数   m:玩家
struct Edge{
      int father;
      vector<int> sons;
      int watch_time;
      int count_ans;
};
Edge Tree[MM];

pair<int ,int> player[MM];


vector< pair<int ,int> > euler;
int  index[MM];

void dfs(int root,int deep){

      cout <<  root <<"  "<< deep <<"  "<< endl;
      euler.push_back( make_pair(root, deep) );

      for( int i=0; i <  Tree[root].sons.size(); i++){

            if( Tree[root].sons[i] !=0 )
                  dfs( Tree[root].sons[i], deep+1 );

      }
      euler.push_back( make_pair( root ,deep ));
}





int LCA(int s, int t){

      dfs(1,0);

      #ifdef debug
            for(int i=0;i<euler.size();i++){
              cout << i << "  "<<  euler[i].first << "  "<<  euler[i].second<< "  "<<endl;
      }
     #endif

      for(int i=0;i<euler.size();i++){
             index[ euler[i].first ] = i;  //这个节点在第i位置被访问。
      }

      int ans=100000;
      for( int i =  index[s] ;i<= index[t] ;i++ ){
            ans = min( ans, euler[i].second );
      }
      return ans;

}



void solve(){

       for(int i=1;i<=m;i++){
           int lca = LCA( player[i].first, player[i].second );
            //没注意到  样例中 2 到根以后,还要向下。。。

            int s= player[i].first;
            int t = player[i].second;

            int time=0;
            while(s!=lca){
                  s = Tree[s].father;
                  time++;
                  if( Tree[s].watch_time==time) Tree[s].count_ans++;
                  #ifdef debug
                    cout <<  "Tree[s].watch_time" << Tree[s].watch_time<< "  ";
                    cout << "time" <<time <<"  " ;
                    cout <<" Tree[s].count_ans " << Tree[s].count_ans << " ";
                    cout << endl;
                  #endif
             }


             if( Tree[lca].watch_time==time++)  Tree[lca].count_ans++;

             stack<int> tmp;

             while(t!=lca){
                  tmp.push(t);
                  t=Tree[s].father;
             }

             while(!tmp.empty()){
                  int f=tmp.top();
                  tmp.pop();
                  if( Tree[f].watch_time==time++)  Tree[f].count_ans++;

                   #ifdef debug
                    cout <<  "Tree[f].watch_time" << Tree[f].watch_time<< "  ";
                    cout << "time" <<time <<"  " ;
                    cout <<" Tree[f].count_ans " << Tree[f].count_ans << " ";
                    cout << endl;
                  #endif
             }



       }
}

int main()
{
	cin>>n>>m;

	for(int i=1; i<=n-1; i++){
            int  a,b;
            cin >>  a >> b;
            Tree[b].father = a;
            Tree[a].sons.push_back( b );
      }

	for(int i=1 ;i<=n; i++){
            cin >> Tree[i].watch_time;
	}

	for(int i=1;i<=m;i++){
            cin >>  player[i].first;
            cin >>  player[i].second;
	}

      solve();

	for(int i=1 ;i<=n; i++){
            cout << Tree[i].count_ans<<endl;
	}

	return 0;
}


这个大佬的博客,写得挺好:

http://blog.csdn.net/herano/article/details/56687381

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值