• 【做题】Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆环


    前言:结论题似乎是我的硬伤……

    题意是给你一个无向图,已知连接到每一个点的边的权值和(为整数,且属于区间[-n,n]),需要求出每条边权值的一个合法解(都要是在区间[-2*n^2,2*n^2]内的整数)。

     第一个想法当然是O(n^2*m)的高斯消元。在此基础上,我想过通过选取某些节点,在边权总和中减去与之相邻的边,来逐个解出边的权值。这个本质上是优化解方程的办法难以适应全部情况,且难以通过编程实现。于是只能舍弃这个想法。

    后来通过漫无边际的瞎想观察标题,容易发现对于一棵树求解这个问题是极为容易的。于是下一个思路就是把这个无向图转化为一棵树。如下图所示,偶环的情况是很容易就能解决的。(无脑删边)

    那么奇环怎么办呢?事实上,本人就卡在了这里。如果按照偶环的方法来解释奇环删边的合法性,我们发现最终有一个点的点权增加了2a。陷入僵局。这时,不妨让我们再考虑一下对树求解的过程。也就是一次dfs,对于除根结点之外的每一个结点都满足其权值和,再根据根结点是否满足其约束条件来判断是否有解。注意到上面奇环的操作,实质就意味着如果我们以一个奇环上的点为根结点,那么就可以在最后判断的时候任意加上一个偶数了。容易证明,最后与根结点相邻的边权和与其应有的边权和之差一定是一个偶数。也就是说,有奇环的图是一定有解的。因此,我们如上的处理奇环的方式,并不会影响解的存在性。

    于是,我们就得到了处理环的方式:都不鸟它,并从奇环上随意拉一个点当根结点。

    讲到这里,我们似乎还忽略了一个条件。

    write a weight between  - 2·n2 and n2 (inclusive) on each edge

    当然,这个范围是相当大的,一般而言解是一定在这个区间内的(也仅限一般而言)。基于cf是一个有hack机制的网站,毫无疑问会有数据把你的解卡出这个区间(对本人而言是test 34)。因此,random_shuffle是必不可缺的

    时间复杂度O(n+m)。

      1 #include <bits/stdc++.h>
      2 #define int long long
      3 #define tag(i) (ed[((i)|1)>>1].id)
      4 using namespace std;
      5 const int N = 100010;
      6 struct edge {
      7     int la,b;
      8     edge(int la=0,int b=0):la(la),b(b) {};
      9 } con[N<<1];
     10 int tot=1,fir[N];
     11 void add(int from,int to) {
     12     con[++tot] = edge(fir[from],to);
     13     fir[from] = tot;
     14     con[++tot] = edge(fir[to],from);
     15     fir[to] = tot;
     16 }
     17 int c[N],ans[N],n,m,cnt,dep[N],rt,ano,fat[N],up[N],mar[N];
     18 typedef pair<int,int> pii;
     19 struct data {
     20     int a,b,id;
     21     data(int a=0,int b=0,int id=0):a(a),b(b),id(id){}
     22 } ed[N];
     23 pii ext[N];
     24 bool vis[N];
     25 void dfs_init(int pos,int fa) {
     26     fat[pos] = fa;
     27     vis[pos] = 1;
     28     dep[pos] = dep[fa] + 1;
     29     for (int i = fir[pos] ; i ; i = con[i].la) {
     30         if (con[i].b == fa) continue;
     31         if (vis[con[i].b]) {
     32             if (pos > con[i].b) ext[++cnt] = pii(pos,i);
     33         } else dfs_init(con[i].b,pos),up[con[i].b] = tag(i);
     34     }
     35 }
     36 int dfs(int pos,int fa) {
     37     vis[pos] = 1;
     38     int now = c[pos];
     39     for (int i = fir[pos] ; i ; i = con[i].la) {
     40         if (vis[con[i].b]) continue;
     41         now -= (ans[tag(i)] = dfs(con[i].b,pos));
     42     }
     43     return now;
     44 }
     45 bool ocy(pii x) {
     46     int a = x.first, b = con[x.second].b;
     47     return (dep[a] + dep[b] + 1)&1;
     48 }
     49 void print() {
     50     puts("YES");
     51     for (int i = 1 ; i <= m ; ++ i) {
     52         cout << ans[i] << endl;
     53     }
     54 }
     55 void modify(int x,int y) {
     56     int k1 = 1, k2 = -1;
     57     while (dep[x] > dep[y]) {
     58         mar[up[x]] += k1;
     59         k1 = -k1;
     60         x = fat[x];
     61     }
     62     while (dep[y] > dep[x]) {
     63         mar[up[y]] += k2;
     64         k2 = -k2;
     65         y = fat[y];
     66     }
     67     while (x != y) {
     68         mar[up[x]] += k1;
     69         k1 = -k1;
     70         x = fat[x];
     71         mar[up[y]] += k2;
     72         k2 = -k2;
     73         y = fat[y];
     74     }
     75 }
     76 signed main() {
     77     int a,b;
     78     cin >> n >> m; 
     79     for (int i = 1 ; i <= n ; ++ i) cin>>c[i];
     80     for (int i = 1 ; i <= m ; ++ i) {
     81         cin >> a >> b;
     82         ed[i] = data(a,b,i);
     83     }
     84     random_shuffle(ed+1,ed+m+1);
     85     for (int i = 1 ; i <= m ; ++ i) add(ed[i].a,ed[i].b);
     86     dfs_init(1,0);
     87     for (int i = 1 ; i <= cnt ; ++ i) {
     88         if (ocy(ext[i])) {
     89             rt = ext[i].first, ano = con[ext[i].second].b;
     90             modify(rt,ano);
     91             mar[tag(ext[i].second)] ++;
     92             break;
     93         }
     94     }
     95     memset (vis,0,sizeof vis);
     96     if (rt) {
     97         int uns = dfs(rt,0)>>1;
     98         for (int i = 1 ; i <= m ; ++ i) ans[i] += mar[i] * uns;
     99         print();
    100     } else {
    101         if (dfs(1,0) != 0) puts("NO");
    102         else print();
    103     }
    104     return 0;
    105 }

    小结:关于我卡在奇环无从下手,应该是缺乏与实际算法的运行相结合。

  • 相关阅读:
    Android 操作系统架构开篇
    《构建之法》读后感
    《梦断代码》读后感
    学习日报
    学习日报
    记账本开发4
    记账本开发3
    学习日报
    学习日报
    记账本开发2
  • 原文地址:https://www.cnblogs.com/cly-none/p/8092684.html
Copyright © 2020-2023  润新知