zoukankan      html  css  js  c++  java
  • @atcoder


    @description@

    给定两棵树 A, B。现你需要构造一组值 (X1, X2, ..., XN)(两棵树编号相同的点对应权值相同),使得两棵树内任意子树的权值和的绝对值为 1。

    无解输出 IMPOSSIBLE。

    原题链接。

    @solution@

    由于权值和为 1,可以推算出每个结点的奇偶性。如果两棵树中同一结点权值奇偶性不同则无解。

    考虑已知每个结点权值的奇偶性之后是否能够构造出一组解。
    既然是构造题,从简原则,猜想偶点总是为 0,奇点总是为 1 或 -1。
    手玩一下样例发现是对的。

    那么相当于给每个奇点染黑白色,使得每棵子树内黑白点个数相差为 1。

    然后就开始玄幻起来了。我们对于每个奇点 i,在两棵树 A, B 的结点 Ai, Bi 之间连一条边。
    注意到此时新图中只有两棵树的根度数可能为奇数,所以我们从根出发跑欧拉路径。
    如果欧拉路径中 Ai->Bi 则 i 为黑点(-1),否则 i 为白点(1)。

    正确性理解起来不难:对于每个连通块(子树),进入连通块的广义 “入度” 与从连通块出的广义 “出度” 是相等的。
    而子树向外只有两类边:连向父亲(只有一条);连向另一棵树。也就是连向另一棵树的边(奇点之间的边)入边与出边相差 1,就是我们的构造目标。

    @accepted code@

    #include <cstdio>
    
    const int MAXN = 200000;
    const int MAXM = 8*MAXN;
    
    struct edge{
    	int to; bool tag;
    	edge *nxt, *rev;
    }edges[MAXM + 5], *adj[MAXN + 5], *ecnt = edges;
    
    void addedge(int u, int v) {
    	edge *p = (++ecnt), *q = (++ecnt);
    	p->to = v, p->tag = false, p->nxt = adj[u], adj[u] = p;
    	q->to = u, q->tag = false, q->nxt = adj[v], adj[v] = q;
    	p->rev = q, q->rev = p;
    }
    
    int X[MAXN + 5], N;
    void dfs(int x) {
    	for(;adj[x];) {
    		edge *p = adj[x]; adj[x] = adj[x]->nxt;
    		if( p->tag ) continue;
    		p->tag = p->rev->tag = true;
    		dfs(p->to);
    		if( x - p->to == -N ) X[x] = -1;
    		else if( x - p->to == N ) X[p->to] = 1;
    	}
    }
    
    int cnt[2][MAXN + 5];
    int main() {
    	scanf("%d", &N);
    	int rt1;
    	for(int i=1;i<=N;i++) {
    		int x; scanf("%d", &x);
    		if( x != -1 ) {
    			addedge(x, i);
    			cnt[0][x]++;
    		}
    		else rt1 = i;
    	}
    	for(int i=1;i<=N;i++) {
    		int x; scanf("%d", &x);
    		if( x != -1 ) {
    			addedge(x + N, i + N);
    			cnt[1][x]++;
    		} 
    	}
    	for(int i=1;i<=N;i++) {
    		if( (cnt[0][i] - cnt[1][i]) & 1 ) {
    			puts("IMPOSSIBLE");
    			return 0;
    		}
    		if( !(cnt[0][i] & 1) )
    			addedge(i, N + i);
    	}
    	dfs(rt1);
    	puts("POSSIBLE");
    	for(int i=1;i<=N;i++)
    		printf("%d%c", X[i], (i == N ? '
    ' : ' '));
    }
    

    @details@

    仿佛发现了比网络流建模更难的东西.jpg。
    不愧是 AGC,轻易就出了一道人类智慧题。

    有一个小细节:整棵树作为一棵子树,是没有向上连向父亲的边的。所以证明时还要特殊讨论一下(不过总之证得出来)。

  • 相关阅读:
    Dilworth定理,链还是反链?
    pku 3259Wormholes
    hdu 2612 Find a way
    hdu 2614
    hdu 2544 最短路
    hdu 2553 N皇后问题
    hdu2717 Catch That Cow
    hdu 1874 畅通工程续
    jquery学习必备代码和技巧
    HTML5 WebApp part4:使用 Web Workers 来加速您的移动 Web 应用程序(上)
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12234568.html
Copyright © 2011-2022 走看看