2020-hdu多校-2

 ACM 󰈭 1550字

6763 1001 并查集

题目出锅了 虽然开局一堆人A的飞快,但是应该都是假算法?主要是出题人给的题解是假的

如果从每次都尽可能删除极大联通块的策略来考虑,那么可以用并查集维护信息。显然在一个极大联通块中可以将每个节点删去所有权值中的最小值,之后该点断裂,将原联通块分成若干个小联通块,反复进行上述操作即可。我们用并查集反向维护这个过程:将所有节点按照权值从大到小进行遍历,如果当前点$u$连有边$<u,v>$并且有$w[v] > w[u]$,那么就在并查集中连$<root[v]->u>$ 。这样, 我们最终就会得到一颗有根树,其上节点的父子关系也给出了删去权值的方案。最终只需要用w[x] - w[par[x]]​去更新答案即可。

因为使用路径压缩的并查集,所以要额外存一个数组,表示真正的拓扑结构上的父节点,用于最后更新答案。

cpp
 1const int maxn = 1e5 + 10;
 2
 3struct star{int to, next;};
 4int n, m, head[maxn], top = 0;
 5int w[maxn];
 6star edge[maxn << 2];
 7
 8void add(int u, int v){
 9    edge[top].to = v;
10    edge[top].next = head[u];
11    head[u] = top++;
12}
13
14bool cmp(int a, int b){return w[a] > w[b];}
15int id[maxn], vis[maxn];;
16
17int par[maxn], f[maxn];
18int find(int x){return x == par[x]? x: par[x] = find(par[x]);}
19
20int main(){
21//    Fastin;
22    int t; scanf("%d", &t); while(t--){
23        clr(head, -1); top = 0; clr(vis, 0);
24        scanf("%d %d", &n, &m);
25        for(int i = 1; i <= n; i++){
26            scanf("%d", w + i);
27            id[i] = i; par[i] = i; f[i] = 0;
28        }
29        for(int i = 0; i < m; i++){
30            int u, v; scanf("%d %d", &u, &v); add(u, v); add(v, u);
31        }
32        sort(id + 1, id + n + 1, cmp);
33        for(int i = 1; i <= n; i++){
34            vis[id[i]] = 1;
35            for(int j = head[id[i]]; ~j; j = edge[j].next){
36                int to = edge[j].to; if(vis[to]){
37                    int r = find(to);
38                    if(r != id[i]) par[r] = f[r] = id[i];
39                }
40            }
41        }
42        ll ans = 0;
43        for(int i = 1; i <= n; i++) ans += w[i] - w[f[i]];
44        printf("%lld\n", ans);
45    }
46    return 0;
47}

1012

cpp
 1
 2const int maxn = 1e5 + 10;
 3const int inf = 1e9;
 4int n, m;
 5char s[maxn], t[30];
 6
 7int nxt[maxn][26], temp[26];
 8int dp[30][30];
 9
10int main(){
11//    Fastin;
12    int __; scanf("%d", &__); while(__--){
13        scanf("%s %s", s + 1, t + 1); n = (int)strlen(s + 1); m = (int)strlen(t + 1);
14        
15        for(int i = 0; i < 26; i++) temp[i] = inf;
16        for(int i = n; i >= 0; i--){
17            for(int j = 0; j < 26; j++) nxt[i][j] = temp[j];
18            if(i) temp[s[i] - 'a'] = i;
19        }
20        int q; scanf("%d", &q); for(int i = 0; i < q; i++){
21            int l, r; scanf("%d %d", &l, &r);
22            //dp[i][j]表示处理t串的第i位后,已经有lcs长为j时,s串中最短的前缀位置
23            dp[1][0] = l - 1; dp[1][1] = s[l] == t[1]? l: nxt[l][t[1] - 'a'];
24            for(int i = 2; i <= m; i++) dp[1][i] = inf;
25            
26            for(int i = 2; i <= m; i++){
27                for(int j = 1; j <= i; j++){
28                    dp[i][0] = dp[i - 1][0]; dp[i][j] = dp[i - 1][j];
29                    if(dp[i - 1][j - 1] <= r && nxt[dp[i - 1][j - 1]][t[i] - 'a'] <= r)
30                        dp[i][j] = min(dp[i][j], nxt[dp[i - 1][j - 1]][t[i] - 'a']);
31                }
32                for(int j = i + 1; j <= m; j++) dp[i][j] = inf;
33            }
34            
35            int lcs = 0;
36            for(int i = 1; i <= m; i++) if(dp[m][i] <= r) lcs = i;
37
38            printf("%d\n", r - l + 1 + m - 2 * lcs);
39        }
40    }
41    return 0;
42}
43 
cpp
  1#include <iostream>
  2    
  3#include <algorithm>
  4#include <string>
  5#include <vector>
  6#include <stack>
  7#include <queue>
  8#include <set>
  9#include <map>
 10#include <unordered_map>
 11#include <unordered_set>
 12#include <random>
 13#include <chrono>
 14   
 15#include <cstdio>
 16#include <cstring>
 17#include <cmath>
 18#include <ctime>
 19#include <cstdlib>
 20#include <cassert>
 21    
 22#define itn int
 23#define fro for
 24#define scnaf scanf
 25#define sacnf scanf
 26#define Fastin freopen("in.txt", "r", stdin)
 27#define Fastout freopen("out.txt", "w", stdout)
 28#define manx maxn
 29#define lowbit(x) ((x) & (-x))
 30#define ceil(n, p) (((n) +(p) - 1) / (p))
 31#define DBG(x) (void)(cout << "L" << __LINE__ << ": " << #x << " = " <<( x) << '\n')
 32#define clr(a, x) memset((a), x, sizeof (a))
 33#define min(a, b) ((a) < (b)? (a): (b))
 34#define max(a, b) ((a) > (b)? (a): (b))
 35   
 36using namespace std;
 37typedef long long ll;
 38   
 39int read(){
 40   int ng=0,x=0;
 41   char ch=getchar();
 42   for(;ch<'0' || ch>'9';ch=getchar()) ng|=ch=='-';
 43   for(;ch>='0' && ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
 44   return ng?-x:x;
 45}
 46/*------------------------------------------------------------------------------------*/
 47ll gcd(ll x, ll y){return !x? y: gcd(y % x, x);}
 48void exgcd(ll a, ll b, ll &x, ll &y){
 49    if(!b){x = 1; y = 0;return;}
 50    exgcd(b, a % b, y, x); y -= a / b * x;
 51}
 52ll qp(ll a, ll p){
 53    if(p < 0) return 0;
 54    ll ans = 1; while(p){if(p & 1) ans = ans * a ; a = a * a; p >>= 1;}
 55    return ans;
 56}
 57ll qp(ll a, ll p, ll M){
 58    ll ans = 1; while(p){ if(p & 1) ans = ans * a % M; a = a * a % M; p >>= 1;}
 59    return ans;
 60}
 61/*------------------------------------------------------------------------------------*/
 62
 63const int manx = 2e4 + 10;
 64
 65struct star{int to, next, a, b;};
 66int n, k;
 67int head[maxn], top = 0;
 68star edge[maxn << 1];
 69void add(int u, int v, int a, int b){
 70    edge[top].to = v;
 71    edge[top].next = head[u];
 72    edge[top].a = a; edge[top].b = b;
 73    head[u] = top++;
 74}
 75
 76
 77//检验树直径<=x 的可能性
 78ll dp[maxn][25], middle, h[25], size[maxn];
 79void dfs(int now, int par){
 80    int pre = 0; dp[now][0] = 0;
 81    for(int id = head[now]; ~id; id = edge[id].next){
 82        int to = edge[id].to; if(to == par) continue;
 83        
 84        dfs(to, now);
 85        for(int i = 0; i <= k && i <= pre + size[to]; i++) h[i] = middle + 1;
 86        for(int i = 0; i <= pre; i++) for(int j = 0; j < size[to] && j + i <= k; j++){
 87            if(dp[now][i] + dp[to][j] + edge[id].a <= middle)
 88                h[i + j + 1] = min(h[i + j + 1], max(dp[now][i], dp[to][j] + edge[id].a));
 89            if(dp[now][i] + dp[to][j] + edge[id].b <= middle)
 90                h[i + j] = min(h[i + j], max(dp[now][i], dp[to][j] + edge[id].b));
 91        }
 92        
 93        for(int i = 0; i <= pre + size[to]; i++) dp[now][i] = h[i];
 94        pre += size[to];
 95    }
 96    size[now] = pre + 1;
 97}
 98
 99
100
101int main(){
102//    Fastin;
103    int _; scanf("%d", &_); while(_--){
104        top = 0;
105
106        scanf("%d %d", &n, &k); for(int i = 0; i < 2 * n; i++) head[i] = -1;
107        ll M =0 ;
108        for(int i = 0; i < n - 1; i++){
109            int u, v, a, b;
110            scanf("%d %d %d %d", &u, &v, &a, &b);
111            add(u, v, a, b);
112            add(v, u, a, b);
113            M += max(a, b);
114        }
115        ll left = 1, right = M;
116        while(left < right){
117            middle = (left + right) >> 1;
118            dfs(1, 0);
119            if(dp[1][k] <= middle) right = middle;
120            else left = middle + 1;
121        }
122        printf("%lld\n", left);
123    }
124    return 0;
125}
嗨! 这里是 rqdmap 的个人博客, 我正关注 GNU/Linux 桌面系统, Linux 内核 以及一切有趣的计算机技术! 希望我的内容能对你有所帮助~
如果你遇到了任何问题, 包括但不限于: 博客内容说明不清楚或错误; 样式版面混乱; 加密博客访问请求等问题, 请通过邮箱 rqdmap@gmail.com 联系我!
修改日志
  • 2023-09-01 18:14:49 单独划分ACM专题; 移动部分博客进入黑洞归档
  • 2023-05-29 23:05:14 博客结构与操作脚本重构
  • 2023-05-08 21:44:36 博客架构修改升级
  • 2022-11-16 01:27:34 迁移老博客文章内容