SCOI2013 day1 摩托车交易(motorcycle)

题目描述:

先吐槽一下为什么今年题要用纸质的…………又是版权问题么…………

然后数据因为版权…………没法得到,所以现在只能在电子科大OJ上提交题目(真搞不懂,数据什么时候也不公开了…………)。

 

首先很明显这道题要求我们找两点之间最小边的最大值,然后能买尽量买,能卖尽量卖,贪心走一遍就好了。考试的时候没有想出来正确的解法,于是上了一个类似弗洛伊德的DP,悲剧的是忘了处理列车站的情况,然后中间也是各种差错导致挂零…………悲剧的人生啊……

其实这个问题很简单,两点之间的最小边的最大值一定存在于最大生成树上(因为最大生成树上两点之间的路径是所有路径中包含的边中权值最大的几条),然后就成了在最大生成树上倍增了,此题瞬间变水题……无语啊……为什么我这么弱……………………T T

需要注意的:1.有列车站的城市需要缩成一个点来做。

      2.中途的黄金有可能超过int,因此在倍增的时候返回INF的话一定要返回long long的INF。

我的代码,求神牛们轻虐……

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 typedef long long ll;
  7 #define min(a,b) ((a)<(b)?(a):(b))
  8 #define max(a,b) ((a)>(b)?(a):(b))
  9 const ll INF=0x3f3f3f3f3f3f3f3fll;
 10 const int MAXN=100010;
 11 const int MAXM=500010;
 12 
 13 struct Edge
 14 {
 15     int st,ed,val;
 16     bool operator < (const Edge &a) const
 17     {
 18         return val>a.val;
 19     }
 20 }edge[MAXM];
 21 struct Node
 22 {
 23     int end,val;
 24     Node *next;
 25 }edge2[MAXN<<1],*head[MAXN];
 26 
 27 int n,m,q,all,all2,gold[MAXN],ord[MAXN],lb[MAXN];
 28 int set_fa[MAXN],fa[MAXN][22],dis[MAXN][22],dep[MAXN];
 29 int que[MAXN];
 30 
 31 int find_set(int a)
 32 {
 33     if (set_fa[a]==a) return a;
 34     return set_fa[a]=find_set(set_fa[a]);
 35 }
 36 void union_set(int a,int b)
 37 {
 38     int f1=find_set(a);
 39     int f2=find_set(b);
 40     if (f1!=f2) set_fa[f1]=f2;
 41 }
 42 void add_edge(int a,int b,int v)
 43 {
 44     edge[all].st=a,edge[all].ed=b,edge[all++].val=v;
 45 }
 46 void add_tree_edge(int a,int b,int v)
 47 {
 48     edge2[all2].end=b,edge2[all2].val=v,edge2[all2].next=head[a],head[a]=edge2+(all2++);
 49 }
 50 void make_tree()
 51 {
 52     int choose=0,all=-1;
 53     if (!q) q=1;
 54     while (choose<n-q)
 55     {
 56         ++all;
 57         if (find_set(edge[all].st)!=find_set(edge[all].ed))
 58         {
 59             ++choose;
 60             add_tree_edge(edge[all].st,edge[all].ed,edge[all].val);
 61             add_tree_edge(edge[all].ed,edge[all].st,edge[all].val);
 62             union_set(edge[all].st,edge[all].ed);
 63         }
 64     }
 65     int front=0,rear=1,t;
 66     dep[que[rear]=(lb[1]?n+1:1)]=1;
 67     while (front!=rear)
 68     {
 69         t=que[++front];
 70         for (Node *p=head[t];p;p=p->next)
 71             if (p->end!=fa[t][0])
 72             {
 73                 fa[p->end][0]=t;
 74                 dis[p->end][0]=p->val;
 75                 dep[p->end]=dep[t]+1;
 76                 que[++rear]=p->end;
 77             }
 78     }
 79     for (int k=1;k<=20;++k)
 80         for (int i=1;i<=n+1;++i)
 81         {
 82             if (lb[i]) continue;
 83             fa[i][k]=fa[fa[i][k-1]][k-1];
 84             dis[i][k]=min(dis[i][k-1],dis[fa[i][k-1]][k-1]);
 85         }
 86 }
 87 ll get_val(int a,int b)
 88 {
 89     if (lb[a]) a=n+1;
 90     if (lb[b]) b=n+1;
 91     if (a==b) return INF;
 92     int i;ll ans=INF;
 93     if (dep[a]<dep[b]) swap(a,b);
 94     for (i=20;~i;--i) if (dep[fa[a][i]]>=dep[b]) ans=min(ans,dis[a][i]),a=fa[a][i];
 95     if (a==b) return ans;
 96     for (i=20;~i;--i) if (fa[a][i]!=fa[b][i]) ans=min(ans,min(dis[a][i],dis[b][i])),a=fa[a][i],b=fa[b][i];
 97     return min(ans,min(dis[a][0],dis[b][0]));
 98 }
 99 int main()
100 {
101     freopen("motorcycle.in","r",stdin);
102     freopen("motorcycle.out","w",stdout);
103     int x,y,z;
104     scanf("%d%d%d",&n,&m,&q);
105     for (int i=1;i<=n+1;++i)
106         set_fa[i]=i;
107     for (int i=1;i<=n;++i)
108         scanf("%d",&ord[i]);
109     for (int i=1;i<=n;++i)
110         scanf("%d",&gold[i]);
111     while (m--)
112     {
113         scanf("%d%d%d",&x,&y,&z);
114         add_edge(x,y,z);
115     }
116     for (int i=1;i<=q;++i)
117     {
118         scanf("%d",&x);
119         lb[x]=1;
120     }
121     for (int i=0;i<all;++i)
122     {
123         if (lb[edge[i].st]) edge[i].st=n+1;
124         if (lb[edge[i].ed]) edge[i].ed=n+1;
125     }
126     sort(edge,edge+all);
127     make_tree();
128     ll now=max(gold[ord[1]],0),now_v;
129     if (gold[ord[1]]<0) puts("0");
130     for (int i=2;i<=n;++i)
131     {
132         now_v=get_val(ord[i-1],ord[i]);
133         if (gold[ord[i]]>0)
134             now=min(now,now_v)+gold[ord[i]];
135         else 
136         {
137             now=min(now,now_v);
138             printf("%lld\n",min(-gold[ord[i]],now));
139             now=max(now+gold[ord[i]],0);
140         }
141     }
142     return 0;
143 }
View Code
posted on 2013-06-01 15:15  stickjitb  阅读(378)  评论(0编辑  收藏  举报