糯米

TI DaVinci, gstreamer, ffmpeg
随笔 - 167, 文章 - 0, 评论 - 47, 引用 - 0
数据加载中……

POJ 1733 Parity game 牛题 -> 并查集+hash

思路:

这题是道好题!
假比确定了 [2, 4]、[5, 6]、[7, 8] 的奇偶性
[4, 5] 的奇偶性无法得知
[2, 6] 的奇偶性是知道的
所以只有询问的区间符合以下要求:
1. 头部和某个已知区间的头部重合
2. 尾部和某个已知区间的尾部重合
3. 区间内每一段都是已知的
才能得出结论

我只想到这一步,然后用链表写了一遍,TLE 了。上网搜解题报告,看到“并查集”三字,恍然大悟。吗的太牛逼了。

我们把首尾相接的多个已知区间归为一类。
将这多个区间的尾部的点归在同一个集合中。
它们的父亲就是最左边区间头部。
它们的权值就是从左边区间头部的到自己的这段区间的奇偶性。

插入区间 [i, j] 的时候,首先查找 i, j 对应的父亲。就是 find 操作。
如果它们的父亲相同,则表明它们处在同一个段的多个已知区间中。
那么 i, j 的权值相减,就很容易得出 [i, j] 的奇偶性了。
如果它们的父亲不同,则需要将 i, j 分别对应的区间段关联起来。也就是 union 操作。
这时候要注意判断 i, j 父亲的位置先后。因为这个 WA 了一次。

由于节点的位置分得很散,用 hash 存放。

#include <stdio.h>

#define HASH_SIZE (1 << 18)
#define NODES_NR 65536

struct node {
    
struct node *root, *next;
    
int idx, val;
}
;

struct node *hash[HASH_SIZE], nodes[NODES_NR];
int nodes_cnt;

inline 
void find(struct node *t)
{
    
static struct node *stk[NODES_NR];
    
int i;

    
for (i = 0; t->root != t; t = t->root)
        stk[i
++= t;
    
for (i--; i >= 0; i--{
        stk[i]
->val += stk[i]->root->val;
        stk[i]
->root = t;
    }

}


inline 
struct node *insert(int idx)
{
    
int h;
    
struct node *t;

    h 
= idx & (HASH_SIZE - 1);
    
for (t = hash[h]; t; t = t->next) {
        
if (t->idx == idx)
            
break;
    }

    
if (!t) {
        t 
= &nodes[nodes_cnt++];
        t
->root = t;
        t
->idx = idx;
        t
->next = hash[h];
        hash[h] 
= t;
    }

    
return t;
}


inline 
int solve(int start, int end, int val)
{
    
struct node *a, *b;

    a 
= insert(start);
    b 
= insert(end);
    find(a);
    find(b);

    
if (a->root == b->root)
        
return ((b->val - a->val) & 1== val;

    val 
-= b->val;
    val 
+= a->val;
    a 
= a->root;
    b 
= b->root;
    
if (a->idx < b->idx) {
        b
->root = a;
        b
->val = val;
    }
 else {
        a
->root = b;
        a
->val = -val;
    }


    
return 1;
}


int main()
{
    
int n, i, x, a, b;
    
char str[16];

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d"&n, &x);
    
for (i = 0; i < x; i++{
        scanf(
"%d%d%s"&a, &b, str);
        
if (!solve(a, b + 1, str[0== 'o'))
            
break;
    }

    printf(
"%d\n", i);

    
return 0;
}



posted on 2010-04-22 21:38 糯米 阅读(866) 评论(0)  编辑 收藏 引用 所属分类: POJ


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理