ACdream原创群赛(11)の风神日华神专场 G - 风之国

G - 风之国

Time Limit:  6000/3000MS (Java/Others)  Memory Limit:  65536/32768KB (Java/Others)
Problem Description

在X轴上有这样一个国家——风之国。风之国虽然是一个国家,但是却有N个首领,每个首领管辖着各自的一个城市。曾几何时,风之国是非常和睦的国家,可是现在突然出现了一个奶茶妹子,各个城市的首领为了这个妹子,掀起了一场没有妹子,就没有夜晚的战争。
这N个城市坐落于X轴上的一些不重复的点上,并且每个城市都只与其左右相邻的城市相互连通。所以一共会有N-1条道路。战争之前任意两个城市之间可以自由贸易。后来因为这场战争,有K对城市由于重要战略物资不允许连通。
X神(掌管X轴的大神)发现了这一点,试图想利用他的法力来破坏一些道路,使得这K对城市两两之间都无法相互连通。
由于破坏每条道路所消耗的法力可能是不一样的,破坏某条道路所消耗的法力是该道路连通的两个城市之间的距离。所以X神想知道最少需要消耗多少的法力,能够使得这K对城市两两之间不能连通。

Input

输入包含多少数据,对于每组数据:
第一行:N K,表示N个城市,K对不允许连通的城市。(2<=N<=100000,0<=K<=100000)。
接下来一行有N个数字x1, x2, x3......xN,其中xi表示第i个城市在X轴上的位置。且每个城市都在不同的位置上。(1<=xi<=10^9, 1<=i<= N)。
接下来K行:u v,表示城市u和城市v不允许连通。输入可能存在重复。(1<=u,v<=n , 且u!=v)

Output

输出一个数,表示X神至少需要消耗多少的法力来破坏一些路,使得这K对城市之间都彼此不连通。

Sample Input
3 3
63 0 132
2 3
1 3
2 1
3 2
63 0 132
2 3
1 2
Sample Output
132
63
Hint

对于第二组数据:

        城市2和城市3 不允许连通,

        城市1和城市2 不允许连通,

        然而对于城市1和城市3没有要求,可连通,可不连通。


G题

       时间复杂度:O(N*logN)

 

方法一:

先对所有点按照x排下序。然后再把k对矛盾点映射为排序后的下标。

然后就是一个dp

Dp[i]表示i前面(包括i)处理掉所有矛盾点的最小花费。

然后状态转移时dp[j] = min( dp[i] + len(i, i + 1) )..

其中a <= i< j。len(i, i + 1)是i与i+1之间的距离, a是j点前面最大的矛盾起点。

求最小值可以用线段树处理。

求出j点dp值之后,把dp[j] + len(j, j + 1)插入到线段树中j位置。

 

方法二:(YY乱搞版)

同样先对所有点按照x排下序。然后再把这K对矛盾点映射为排序后的下标(u,v),并使得u<v,然后对这k对矛盾按照右端点v进行从小到大排个序。

然后就是一个乱搞yy的过程。

对于排序后的K对矛盾,按照顺序进行下列步骤:

第一步:求其不允许连通的两个点路径上的最小边,记为Min_E ;

第二步:然后 Ans+=Min_E ;

第三步:再把路径上所有的边的权值都减去最小边的权值。

如此,处理完K对矛盾后,Ans就是答案。

       经过我100W的数据对拍,由此得证该方法的正确性!O(∩_∩)O~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
 
using namespace std;
 
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
 
 
 
const int inf = 0x7f7f7f7f;
const int maxn = 111111;
 
inline int scanf ( int &num)
{
     char in;
     bool neg= false ;
     while ((in= getchar ())!=EOF && (in> '9' || in< '0' ) && in!= '-' );
     if (in==EOF)  return 0;
     else if (in== '-' ) neg= true ,num=0;
     else  num=in- '0' ;
     while (in= getchar (),in>= '0' && in<= '9' ) num*=10,num+=in- '0' ;
     if (neg) num=-num;
     return 1;
}
 
struct SegTree {
     int dp[maxn << 2];
     void build( int l,  int r,  int rt) {
         dp[rt] = inf;
         if (l == r)  return ;
         int m = (l + r) >> 1;
         build(lson); build(rson);
     }
     void update( int x,  int val,  int l,  int r,  int rt) {
         if (l == r) {
             dp[rt] = val;
             return ;
         }
         int m = (l + r) >> 1;
         if (x <= m) update(x, val, lson);
         else update(x, val, rson);
         dp[rt] = min(dp[rt << 1], dp[rt << 1 | 1]);
     }
     int query( int ll,  int rr,  int l,  int r,  int rt) {
         if (ll <= l && r <= rr) {
             return dp[rt];
         }
         int ret = inf;
         int m = (l + r) >> 1;
         if (ll <= m) ret = min(ret, query(ll, rr, lson));
         if (rr > m) ret = min(ret, query(ll, rr, rson));
         return ret;
     }
};
 
struct city {
     int idx, x;
     inline void input( int __idx) {
         //scanf(x);
         scanf ( "%d" , &x);
         idx = __idx;
     }
     inline bool operator < ( const city &a)  const {
         return x < a.x;
     }
};
 
SegTree tree;
int pre[maxn];
city c[maxn];
int mp[maxn];
int n, k;
 
void init() {
     tree.build(0, n, 1);
     memset (pre, -1,  sizeof (pre));
}
 
int main() {
     //freopen("wind.in", "r", stdin);
     //freopen("wind.out", "w", stdout);
     while (~ scanf ( "%d%d" , &n, &k)) {
         init();
         for ( int i = 1; i <= n; i++) {
             c[i].input(i);
         }
         sort(c + 1, c + n + 1);
         for ( int i = 1; i <= n; i++) {
             mp[ c[i].idx ] = i;
         }
         for ( int i = 1; i <= k; i++) {
             int a, b;
             scanf ( "%d%d" , &a, &b);
             //scanf(a); scanf(b);
             a = mp[a]; b = mp[b];
             if (a > b) swap(a, b);
             pre[b] = max(pre[b], a);
         }
         tree.update(0, 0, 0, n, 1);
         int lim = 0;
         int dp;
         for ( int i = 1; i <= n; i++) {
             if (pre[i] != -1) {
                 lim = max(pre[i], lim);
             }
             dp = tree.query(lim, i - 1, 0, n, 1);
             tree.update(i, dp + c[i + 1].x - c[i].x, 0, n, 1);
         }
         printf ( "%d\n" , dp);
     }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值