题解

88 条题解

  • 10
    @ 2017-05-08 08:00:28
    /*
    这道题目很明显是一道并查集题目~
    设f[i]表示从1-i区间内的1的个数的奇偶性
    对于一个查询(a,b)如果答案是偶数
    说明1-(a-1)与1-n的含1个数的奇偶性相同
    即有f[a-1]==f[b]
    否则f[a-1]!=f[b]
    那么对于奇偶性来说就只有两种情况咯
    相同奇偶性或者不同奇偶性
    这就是和关押罪犯那道题有点像只有两种集合
    那么我们用a和a+maxn表示一个对立面
    如果a和b同奇偶就将a,b合为一个集合
    a+maxn,b+maxn也会为相同集合
    否则就说明a的相反面和b同集,b的相反面也和a同集合
    我们就将(a,b+maxn) (b,a+maxn)合并为一个集合
    判断时如果是同奇偶,
    就判断a和b+maxn(或者a+maxn,b)是不是同一个集合,如果是说明矛盾
    否则按上面合并
    同理如果是非同奇偶,
    那么就检查a,b(或者a+maxn,b+maxn)是否是一个集合不是矛盾,
    否则按上面合并即可
    同时我们注意到这个下标大小可能到1000000000
    这实在太大了,我们就想到用hash压缩一下,不然根本放不下
    这道题就这样解决了~orz
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <stack>
    using namespace std;
    
    char rd;    int pn;
    template<typename Type>
    inline void read(Type& v)
    {
        pn=1;
        while((rd=getchar())<'0'||rd>'9')
            if(rd=='-')
                pn=-1;
        v=rd-'0';
        while((rd=getchar())>='0'&&rd<='9')
            v=v*10+rd-'0';
        v*=pn;
    }
    template<typename Type>
    inline void out(Type v,bool c=1)
    {
        if(v==0)
            putchar(48);
        else  
        {
            if(v<0)
            {
                putchar('-');
                v=-v;
            }
            int len=0,dg[20];  
            while(v>0)
            {
                dg[++len]=v%10;
                v/=10;
            }  
            for(int i=len;i>=1;i--)
                putchar(dg[i]+48);  
        }
        if(c)
            putchar('\n');
        else
            putchar(' ');
    }
    
    const int MAXN=30009;
    const int MAXNN=10000;
    const int Hash=6007;
    int fa[MAXN];
    int Map[MAXN];
    int n,m;
    
    inline int find(int x)
    {
        return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    
    void Union(int a,int b)
    {
        a=find(a),b=find(b);
        if(a!=b)
            fa[a]=b;
    }
    
    void init()
    {
        memset(Map,-1,sizeof(Map));
        for(int i=0;i<MAXN;i++)
            fa[i]=i;
        read(n);    read(m);
    }
    
    int change(int x)
    {
        int b=x%Hash;
        while(Map[b]!=-1&&Map[b]!=x)
            b=(b+1)%Hash;
        Map[b]=x;
        return b;
    }
    
    void work()
    {
        int a,b;
        string c;
        int i=1;
        for(;i<=m;i++)
        {
            read(a);    read(b);    cin>>c;
            a=change(a-1);
            b=change(b);
            if(c[0]=='o')
            {
                if(find(a)==find(b))
                    break;
                Union(a,b+MAXNN);
                Union(a+MAXNN,b);
            }
            else
            {
                if(find(a)==find(b+MAXNN))
                    break;
                Union(a,b);
                Union(a+MAXNN,b+MAXNN);
            }
        }
        out(i-1);
    }
    
    int main()
    {
        init();
        work();
    }
         
         
    
  • 2
    @ 2017-07-02 11:19:43

    这题可以用map,但是要注意几个坑点

    #include<stdio.h>
    #include<map> 
    #include<algorithm>
    #define M 1000000003  //这里要开大于1000000000,被坑2次
    using namespace std;
    map<int,int> f;
    int n,m; char s[100];
    int dx(int x){
        int p=f[x];
        if(p==0||p==x) return x;  //这里要注意p==x的情况,因为下面可能出现a=b的情况
        return f[x]=dx(p);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int a,b,i=0;i<m;++i){
            scanf("%d%d%s",&a,&b,s);b++;  
            int c1=dx(a),c2=dx(a+M);
            int d1=dx(b),d2=dx(b+M);
            if(*s=='e'){
                if(c1==d2 || c2==d1) 
                    return 0&printf("%d\n",i);
                else { f[c1]=d1; f[c2]=d2; }
            } else {
                if(c1==d1 || c2==d2)
                    return 0&printf("%d\n",i);
                else { f[c1]=d2; f[c2]=d1; }
            }
        }
        printf("%d\n",m);
    }
    

    具体思路参考楼下?

  • 1
    @ 2016-11-14 22:05:17

    看了一下,没人发向量偏移的,那我就发一个

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MOD 50000
    using namespace std;
    int n,t,book[50005],pre[50005],state[50005];
    int hash_(int x){
    int b=x%MOD;
    while(book[b]!=-1&&book[b]!=x)
    b=(b+1)%MOD;
    book[b]=x;
    return b;
    }
    int find(int x){
    if(x==pre[x]) return x;
    int t=pre[x];
    pre[x]=find(pre[x]);
    state[x]=state[t]+state[x];
    return pre[x];
    }
    int main(){
    //freopen("P.in","r",stdin);
    //freopen("P.out","w",stdout);
    int i;
    memset(book,-1,sizeof(book));
    scanf("%d %d",&n,&t);
    for(i=0;i<=50000;i++){
    pre[i]=i;state[i]=0;
    }
    for(i=1;i<=t;i++){
    char s[10];
    int x,y;
    scanf("%d %d %s",&x,&y,s);
    int a=hash_(x-1);
    int b=hash_(y);
    int fx=find(a);
    int fy=find(b);
    if(fx!=fy){
    pre[fy]=fx;
    if(s[0]=='e')
    state[fy]=(state[a]-state[b]+2)%2;
    else if(s[0]=='o')
    state[fy]=(state[a]-state[b]+1+2)%2;
    }
    else if(fx==fy){
    if(s[0]=='e'&&((state[b]-state[a]+2)%2)==1){
    printf("%d",i-1);
    return 0;
    }
    else if(s[0]=='o'&&(state[b]-state[a]+2)%2==0){
    printf("%d",i-1);
    return 0;
    }
    }
    }
    printf("%d",t);
    return 0;
    }

  • 1
    @ 2014-02-08 14:25:56

    此题太神了。

  • 0
    @ 2019-01-29 20:49:31

    Wa

  • 0
    @ 2015-08-21 21:51:56

    不得不说vj的数据实乃业界良心

  • 0
    @ 2015-08-05 21:58:25

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int hash = 6000,MAXN = 10000;
    //离散化的时候要记a-1

    int f[MAXN*2+100], map[hash+100];
    char s[10];

    int Hash(int x){
    int bri = x%hash;
    while(map[bri] != -1 && map[bri] != x)
    bri = (bri+1)%hash;
    map[bri] = x;
    return bri;
    }

    int find(int x){
    if(!f[x])
    return x;
    return f[x] = find(f[x]);

    }

    void add(int a, int b){
    a = find(a);
    b = find(b);
    if(a != b)
    f[a] = b;
    }

    int main()
    {
    memset(map, -1, sizeof(map));
    int n, k, a, b, i;
    scanf("%d%d",&n,&k);

    for(i=1; i<=k; i++){
    scanf("%d%d%s",&a,&b,s);
    a = Hash(a-1);
    b = Hash(b);
    if(s[0] == 'e'){
    if(find(a) == find(b+MAXN))
    break;
    add(a, b);
    add(a+MAXN, b+MAXN);
    }
    else{
    if(find(a) == find(b))
    break;
    add(a, b+MAXN);
    add(a+MAXN, b);

    }
    }
    printf("%d",i-1);
    return 0;
    }
    hash 离散化 并查集

  • 0
    @ 2015-02-03 13:49:27

    注意细节!
    读入数据(a,b,odd/even),离散化的时候要记(a-1,b,odd/even).....

  • 0
    @ 2014-10-19 20:38:22

    Block code

    var n,m,i,j,k,t,max,total:longint;
    b,d,f:array [1..10000] of longint;
    line:array [1..5000,1..3] of longint;
    c:char;
    procedure swap(var a,b:longint);
    var z:longint;
    begin
    z:=a;a:=b;b:=z;
    end;
    function find(x:longint):longint;
    var m:longint;
    begin
    if f[x]=x then exit(x);
    m:=f[x];
    f[x]:=find(f[x]);
    b[x]:=(b[x]+b[m]) mod 2;
    exit(f[x]);
    end;

    procedure sort(i,j:longint);
    var key,x1,x2:longint;
    begin
    if i<j then
    begin
    x1:=i;x2:=j;key:=d[(i+j) shr 1];
    repeat
    while d[x1]<key do inc(x1);
    while d[x2]>key do dec(x2);
    if x1<=x2 then
    begin
    swap(d[x1],d[x2]);
    inc(x1);dec(X2);
    end;
    until x1>x2;
    if x1<j then sort(x1,j);
    if x2>i then sort(i,x2);
    end;
    end;

    function ef(x:longint):longint;
    var l,r,mid:longint;
    begin
    l:=1; r:=total;
    while l<=r do
    begin
    mid:=(l+r) div 2;
    if d[mid]<x then l:=mid+1
    else if d[mid]>x then r:=mid-1
    else exit(mid);
    end;
    exit(-1);
    end;

    procedure union(x,y,p:longint);
    var
    i,x1,x2:longint;
    begin
    x1:=find(x);
    x2:=find(y);
    if (x1<>x2) then
    begin
    f[x1]:=x2;
    i:=b[x]+b[y]+p;
    i:=i mod 2;
    b[x1]:=i;
    end;
    end;

    procedure init;
    var x,y,l,r:longint;
    begin
    readln(n);readln(m);
    for i:=1 to m do
    begin
    read(line[i,1],line[i,2]);
    read(c); readln(c);
    if c='e' then line[i,3]:=0 else line[i,3]:=1;
    d[2*i-1]:=line[i,1]-1;
    d[2*i]:=line[i,2];
    end;
    sort(1,2*m);
    total:=1;
    for i:=2 to 2*m do
    begin
    if d[i]<>d[total] then
    begin
    inc(total);
    d[total]:=d[i];
    end;
    end;
    for i:=1 to total do
    f[i]:=i;
    for i:=1 to m do
    begin
    x:=line[i,1]-1; y:=line[i,2];
    x:=ef(x); y:=ef(y);
    l:=find(x); r:=find(y);
    if l<>r then
    union(x,y,line[i,3])
    else
    begin
    x:=b[x]; y:=b[y];
    if (y+x+line[i,3]+2) mod 2<>0 then
    begin
    writeln(i-1);
    halt;
    end;
    end;
    end;
    writeln(m);
    end;

    begin
    init;
    end.

  • 0
    @ 2014-01-25 11:10:44

    type
    new=record
    l,r:longint;
    f:boolean;
    end;
    var
    n:longint;
    i,j,k,l,m,p:integer;
    s:string;
    ch:char;
    a:array[0..10001] of longint;
    b:array[0..5001] of integer;
    c:array[0..5001] of new;
    procedure sort(l,r:longint);
    var
    i,j,x,y:longint;
    begin
    x:=a[(l+r) div 2];
    i:=l;
    j:=r;
    repeat
    while a[i]<x do inc(i);
    while x<a[j] do dec(j);
    if i<=j then
    begin
    y:=a[i];
    a[i]:=a[j];
    a[j]:=y;
    inc(i);
    dec(j);
    end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r);
    end;
    begin
    readln(n);
    readln(m);
    for i:=1 to m do
    begin
    read(c[i].l,c[i].r);
    a[2*i-1]:=c[i].l-1;
    a[2*i]:=c[i].r;
    read(ch);
    readln(s);
    if ch<>' ' then s:=ch+s;
    if s='even' then c[i].f:=true;
    end;
    sort(1,2*m);
    l:=0;
    for i:=1 to 2*m do
    if (l=0) or (a[i]<>a[l]) then
    begin
    inc(l);
    a[l]:=a[i];
    end;
    for i:=1 to l do b[i]:=i;
    for i:=1 to m do
    begin
    for j:=1 to l do if a[j]=c[i].l-1 then break;
    for k:=j+1 to l do if a[k]=c[i].r then break;
    if (c[i].f and (b[j]+b[k]=0)) or ((not c[i].f) and (b[j]=b[k])) then
    begin
    writeln(i-1);
    exit;
    end;
    if c[i].f then
    if b[j]<>b[k] then
    for p:=1 to l do
    if b[p]=b[k] then b[p]:=b[j] else else else
    if b[j]+b[k]<>0 then
    for p:=1 to l do if b[p]=b[k] then b[p]:=-b[j];
    end;
    writeln(m);
    end.

  • 0
    @ 2013-07-13 20:35:33

    测试数据 #0: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #1: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #2: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #3: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #4: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #5: Accepted, time = 15 ms, mem = 824 KiB, score = 10
    测试数据 #6: Accepted, time = 15 ms, mem = 824 KiB, score = 10
    测试数据 #7: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #8: Accepted, time = 0 ms, mem = 824 KiB, score = 10
    测试数据 #9: Accepted, time = 15 ms, mem = 824 KiB, score = 10
    Accepted, time = 45 ms, mem = 824 KiB, score = 100

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int HASH = 6000, N = 10000;
    int map[HASH + 100], f[N * 2 + 100];
    int n, k;
    int hash(int x)
    {
    int ret;
    ret = x % HASH;
    while(map[ret] != -1 && map[ret] != x)
    ret = (ret + 1) % HASH;
    map[ret] = x;
    return ret;
    }
    int find(int x)
    {
    if(!f[x]) return x;
    return f[x] = find(f[x]);
    }
    void un(int x, int y)
    {
    x = find(x);
    y = find(y);
    if(x != y) f[x] = y;
    }
    int main()
    {
    memset(map, -1, sizeof(map));
    char s[10];
    bool flag;
    scanf("%d%d", &n, &k);
    int i, a, b;
    for(i = 1; i <= k; ++i)
    {
    scanf("%d%d%s", &a, &b, s);
    flag = (0 == strcmp(s, "even")) ? true : false;
    a = hash(a - 1);
    b = hash(b);
    if(flag)
    {
    if(find(a) == find(b + N)) break;
    un(a, b);
    un(a + N, b + N);
    }
    else
    {
    if(find(a) == find(b)) break;
    un(a, b + N);
    un(a + N, b);
    }
    }
    printf("%d", i - 1);
    return 0;
    }

  • 0
    @ 2012-07-25 21:09:00

    问个问题,合并时,为什么f[y]=x只能50分额……

    #include

    #include

    #include

    #include

    using namespace std;

    const int HASH=6000,N=10000;

    int map[HASH+100],f[N*2+100];

    int n,k;

    int hash(int x)

    {

    int ret;

    ret=x%HASH;

    while(map[ret]!=-1 && map[ret]!=x)

    ret=(ret+1)%HASH;

    map[ret]=x;

    return ret;

    }

    int find(int x)

    {

    if(!f[x]) return x;

    return f[x]=find(f[x]);

    }

    void un(int x,int y)

    {

    x=find(x);

    y=find(y);

    if(x!=y) f[x]=y;

    }

    int main()

    {

    memset(map,-1,sizeof(map));

    char s[10];

    bool flag;

    scanf("%d%d",&n,&k);

    int i,a,b;

    for(i=1;i

  • 0
    @ 2012-07-16 22:24:19

    ├ 测试数据 01:答案正确... 0ms 

    ├ 测试数据 02:答案正确... 0ms 

    ├ 测试数据 03:答案正确... 0ms 

    ├ 测试数据 04:答案正确... 0ms 

    ├ 测试数据 05:答案正确... 0ms 

    ├ 测试数据 06:答案正确... 0ms 

    ├ 测试数据 07:答案正确... 0ms 

    ├ 测试数据 08:答案正确... 0ms 

    ├ 测试数据 09:答案正确... 0ms 

    ├ 测试数据 10:答案正确... 0ms 

    ---|---|---|---|---|---|---|---|- 

    Accepted 有效得分:100 有效耗时:0ms 

    1A了

    表示自从ac了食物链后,并查集无压力。

  • 0
    @ 2010-07-24 19:30:12

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 0ms

    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:0ms

    并查集+前向星

  • 0
    @ 2010-03-15 23:53:33

    的确是道好题。我智商实在有限。看了好多题解才明白。

    说的简单点

    就是一个数组 前10000个是same 后10000个是dif

    same[i]表示与i同号的

    dif[i]表示与i异号的

    same[i]=dif[j]可推出 i j odd

    same[i]=same[j] 可推出 i j even

    每次先判断后合并就是了

    如果是odd 就合并 (same[i] dif[j])(dif[i] same[j])

    even就合并(same[i] same[j])(dif[i] dif[j])

  • 0
    @ 2009-11-09 20:30:45

    好题!

    赞一个!

  • 0
    @ 2009-11-08 20:01:27

    并查集,确实是好题!

    困扰了我一下午 囧冏

  • 0
    @ 2009-11-08 19:28:08

    好题啊,每一步都很经典。

    第一行的数据是干啥的,怎么没用到……

  • 0
    @ 2009-11-03 22:22:35

    我真的不是一般的想bs楼下的这位↓

    我以为楼下贡献自己的AC率为大家找到了数据范围,没想到5000这个范围是错的!

    害得我重写了1次、提交了整整10次10。

    起初数组开5000都是答案错误(6000也是),直到我重写之后出现错误号: -1073741571 ,我才意识到数组开小了。。。。。。。。改成10000,秒杀。。。。

    我不是看重AC率,但对于没有数据范围的题目,楼下是唯一一个给出范围的,怎么能让人不信啊?!(实践证明,实践是检验真理的唯一标准)

  • 0
    @ 2009-10-31 21:32:25

    program dsf;

    var n:longint;

    begin

    read(n);

    read(n);

    writeln(n);

    end.

    通过它,知道了问题数是小于5000的,爽!

    • @ 2014-01-16 18:21:20

      话说你坑爹大大草稿行不行,vijos是**不会**显示输出的

信息

ID
1112
难度
6
分类
数据结构 | 并查集 点击显示
标签
递交数
2467
已通过
614
通过率
25%
被复制
12
上传者