首页 > 其他分享 >【题解】「COCI 2018.10」Teoretičar

【题解】「COCI 2018.10」Teoretičar

时间:2022-09-02 23:56:38浏览次数:71  
标签:std sz 2018.10 int 题解 back edge ar push

传送门

题目大意

有一个二分图,构造一种对边的染色方案,使得没有两个颜色相同的边共顶点。

假设对于给定二分图的答案是 \(C\),记 \(X\) 是大于等于 \(C\) 的最小的 \(2\) 的整次幂,你只需要给出一个方案,使得颜色数量不多于 \(X\)。

\(L, R\le 10^5, m\le 5\times 10^5\)

题解

设度数最大的点的度数为 \(D\),那么显然答案 \(C\ge D\),也就是说我们只要构造出一种要颜色数不超过 \(2^{\lceil \log_2 D \rceil}\) 的方案。

假设我们有一个边集 \(E\),如果每个点的度数都 \(\le 1\),那么显然此时答案为 \(1\),否则我们可以考虑把这个边集划分为两个边集 \(E_1, E_2\),使得每个点的度数尽量被平分,即都不超过 \(\lceil\frac D2\rceil\)。

这样递归下去,可以发现我们就能满足限制了。

边的分割可以跑欧拉回路(其中需要适当加虚点和虚边使得每个点的度数都为偶数)。

时间复杂度 \(O(m\log m)\)。

Code
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i=j; i<=k; ++i)
#define ROF(i,j,k) for(int i=j; i>=k; --i)
inline int read (void) {
  int x = 0, f = 1, ch = getchar();
  while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
  while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
  return x * f;
}
const int maxn = 200005;
const int maxm = 500005;
struct Node {
  int x, y, id;
};
int n, m, col, ans[maxm];
std::vector <std::pair <int, int> > edge[maxn];
int lst=2, sz[maxn], Flag[maxm + maxn];
void dfs (int x, int pre=0) {
  while(sz[x]) {
    std::pair <int, int> cur = edge[x].back(); edge[x].pop_back(); -- sz[x];
    if(Flag[cur.second]) continue;
    Flag[cur.second] = 1;
    dfs (cur.first, cur.second);
  } Flag[pre] = lst ^= 1;
}
void solve (std::vector <Node> v) {
  std::vector <int> node;
  for(auto&it:v) {
    ++ sz[it.x]; ++ sz[it.y];
    node.push_back(it.x); node.push_back(it.y);
    edge[it.x].push_back(std::make_pair(it.y, it.id));
    edge[it.y].push_back(std::make_pair(it.x, it.id));
  }
  bool flag = 1;
  for(auto&it:node) if(sz[it] > 1) flag = 0;
  if(flag) {
    ++ col;
    for(auto&it:v) ans[it.id] = col;
    for(auto&it:node) edge[it].clear(), sz[it] = 0;
    return ;
  } int cnt = m;
  for(auto&it:node) if(sz[it]&1) {
    ++ cnt; ++ sz[it]; ++ sz[n + 1];
    edge[it].push_back(std::make_pair(n + 1, cnt));
    edge[n + 1].push_back(std::make_pair(it, cnt));
  } lst = 2; dfs (n + 1);
  for(auto&it:node) dfs (it);
  std::vector <Node> V[2];
  FOR(i,m+1,cnt) Flag[i] = 0;
  for(auto&it:v) {
    V[Flag[it.id] == 2].push_back(it);
    Flag[it.id] = 0;
  }
  solve (V[0]); solve (V[1]);
}
int main (void) {
  int l = read(), r = read(); m = read();
  std::vector <Node> edge; n = l + r;
  FOR(i,1,m) {
    int x = read(), y = read();
    edge.push_back((Node) {x, l + y, i});
  }
  solve (edge);
  printf("%d\n", col);
  FOR(i,1,m) printf("%d\n", ans[i]);
  return 0;
}

标签:std,sz,2018.10,int,题解,back,edge,ar,push
From: https://www.cnblogs.com/Vomedakth/p/16651714.html

相关文章

  • ES6 关键字 let 和 ES5 及以前关键字 var 的区别
    var在ES5及以前,通过var在块级作用域中声明的变量,外边也可以访问。块级作用域就是一对{}的作用域;块级作用域可以是控制语句的作用域,也就是非函数的作用域。functionf()......
  • Typescript类型体操 - First of Array
    题目中文实现一个通用First<T>,它接受一个数组T并返回它的第一个元素的类型。例如:typearr1=['a','b','c']typearr2=[3,2,1]typehead1=First<arr1>//e......
  • Elasticsearch 查询 UV
    ES聚合指标value_count:计数cardinality:去重计数avg:平均值sum:求和max:最大值min:最小值percentiles:百分比top_hits:简单来说就是聚合分组后从每一个......
  • CF diary II
    每\(10\)题一篇\(\texttt{>o<}\)。似乎不只有cf\(\texttt{Difficulty:}\)题意题解代码viewcode......
  • Windows编译 wireshark
    要想编译WireShark:我们需要设置一些环境变量来配置cmake,幸运的是,vscode的CMake插件为我们提供了这个功能,我们只需要在工作区中设置即可:同时需要注意的是,因为wireshark需......
  • Java集合---ArrayList
    集合和数组的区别共同点:都是存储数据的容器 不同点:数组的容量是固定的,集合的容量是可变的ArrayList的构造方法和添加方法publicArrayList()创建一个空......
  • @RequestParam和@PathVariable的用法与区别
    SpringBoot——@PathVariableURL变量Web应用中的URL通常不是一成不变的,例如微博两个不同用户的个人主页对应两个不同的URL:http://weibo.com/user1和http://weibo.com/use......
  • 「题解」Longge 的问题
    原题目链接:Link。虽然已经被A穿了但还是写一下。\[\sum_{i=1}^n\gcd(i,n)=\sum_{d\vertn}\sum_{i=1}^n[\gcd(i,n)=d]\]这一步显然,因为\(\forall\gc......
  • P2858 [USACO06FEB]Treats for the Cows G/S 题解
    [USACO06FEB]TreatsfortheCowsG/S[USACO06FEB]TreatsfortheCowsG/S题目描述FJhaspurchasedN(1<=N<=2000)yummytreatsforthecowswhogetmoneyfo......
  • P1005 [NOIP2007 提高组] 矩阵取数游戏 题解
    luogu原题传送门[NOIP2007提高组]矩阵取数游戏题目描述帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(n\timesm\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非......