FZU2169 shadow题解

http://acm.fzu.edu.cn/problem.php?pid=2169

Problem Description

YL 是shadow国的国王,shadow国有N个城市。为了节省开支,shadow国只有N-1条道路,这N-1条道路使得N个城市连通。某一 年,shadow国发生了叛乱,叛军占领了多个城市,王都岌岌可危。王都为编号为1的城市,除了王都外有K个城市有YL的军队。现在这K支军队要向王都进 军,并且消灭沿途经过的城市中的叛军。现给出N个城市的道路情况以及城市的叛军数量,问总共需要消灭多少叛军?

Input

第 一行输入两个整数N,K,接下来输入N(1<=N<=100000)个整数Ai(0<=Ai<=10000),表示第i个城市的 叛军数量。接下来输入K个大于等于1且小于等于N的整数,表示有军队的城市的编号。数据保证王都以及有军队的城市没有叛军。接下来输入N-1行,每行两个 整数u、v,表示连接u和v的一条道路。每支军队只能沿着道路走,并且是其所在城市与王都之间的最短路线走。

Output

输出一行一个整数表示消灭的叛军数量。

Sample Input

4 2 0 3 0 0 3 4 1 2 2 3 2 4

Sample Output

3

 

题意:N<=10万个点,N-1条边使所有点连通,点编号为1~N,1号点为国王所在地,给出K个编号表示这K个点有国王的军队,给出Ai表示第i个点有Ai个叛军,国王所在地和有国王军的地方没叛军。现在国王的军队以最短路向国王所在地移动,消灭沿途所有叛军,求消灭的叛军数。

 

解:用STL的set记国王军所在地,从国王所在地开始宽搜,从当前点u扩展节点时记录扩展节点v来自哪里,from[v]=u。搜到一个国王军就把之前走的这条路上的点的叛军数加到ans里,并且对沿途的点标记geted[x]=true,一开始先标记国王所在地geted[0]=true,这样每次找到一个国王军就把国王军到geted为true的点之间的叛军数加到ans里,并且统计找到的国王军数cnt++。cnt==K时就找够全部国王军了,结束。是不是很碉,只要一次宽搜就得了耶!

  1 #include<iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include<vector>
  6 #include<queue>
  7 #include<set>
  8 #define MAXN 101111
  9 #define RE freopen("in.txt","r",stdin);
 10 
 11 using namespace std;
 12 
 13 struct Edge
 14 {
 15     int u,v;
 16     int next;
 17 };
 18 Edge e[MAXN*2];
 19 int first[MAXN];
 20 int en;
 21 
 22 void add(int u,int v)
 23 {
 24     e[en].u=u;
 25     e[en].v=v;
 26     e[en].next=first[u];
 27     first[u]=en;
 28     en++;
 29 }
 30 
 31 int n,k,cnt;
 32 int a[MAXN];
 33 set<int> b;
 34 bool walked[MAXN];
 35 bool geted[MAXN];
 36 queue<int> v;
 37 int from[MAXN];
 38 int farm();
 39 void init();
 40 
 41 int main()
 42 {
 43     //RE
 44     while(scanf("%d%d",&n,&k)!=EOF)
 45     {
 46         farm();
 47     }
 48     return 0;
 49 }
 50 
 51 int farm()
 52 {
 53     int i,j,x,y;
 54     init();
 55     for(i=0; i<n; i++)
 56         scanf("%d",&a[i]);
 57     for(i=0; i<k; i++)
 58     {
 59         scanf("%d",&x);
 60         x--;
 61         b.insert(x);
 62     }
 63     for(i=0; i<n-1; i++)
 64     {
 65         scanf("%d%d",&x,&y);
 66         x--;y--;
 67         add(y,x);
 68         add(x,y);
 69     }
 70     long long ans=0;
 71     while(!v.empty()) v.pop();
 72     v.push(0);
 73     walked[0]==true;
 74     geted[0]=true;
 75     while(!v.empty())
 76     {
 77         int now=v.front();
 78         v.pop();
 79         //cout<<now<<'!';
 80         if(b.find(now)!=b.end())
 81         {
 82             //cout<<now<<',';
 83             x=now;
 84             while(!geted[x])
 85             {
 86                 geted[x]=true;
 87                 ans+=a[x];
 88                 x=from[x];
 89             }
 90             cnt++;
 91             if(cnt==k) break;
 92             continue;
 93         }
 94         for(j=first[now]; j!=-1; j=e[j].next)
 95         {
 96             //cout<<j<<'?';
 97             int next=e[j].v;
 98             if(!walked[next])
 99             {
100                 walked[next]=true;
101                 v.push(next);
102                 from[next]=now;
103             }
104         }
105     }
106     printf("%lld\n",ans);
107     return 0;
108 }
109 
110 
111 void init()
112 {
113     memset(e,0,sizeof(e));
114     memset(first,-1,sizeof(first));
115     memset(walked,false,sizeof(walked));
116     memset(geted,false,sizeof(geted));
117     b.clear();
118     cnt=0;
119     en=0;
120 }
View Code

话说我交的时候突然想起set没清空,不过还是过了,难道只有一组数据…

 

 

不过耗时好像比其他方法久……好像可以手动开栈 深搜,我也不太懂怎么弄的

 

posted @ 2014-05-15 21:56  带鱼Yuiffy  阅读(337)  评论(0编辑  收藏  举报