bzoj4644: 经典傻逼题

Posted akcqhzdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4644: 经典傻逼题相关的知识,希望对你有一定的参考价值。

我是弟弟。。。左左睿的神题还是另外一题的真子集

首先令点权为和它相连的边权异或和,容易发现一个点集的割就是点权和

但是m次线性基肯定是不行的

学了个新东西,线段树分治

首先他的下标是时间

对于一个点,他的权值反映在时间轴上就是多段权值

然后插入到线段树上,容易证明如果是一段相同的权值,最多会被拆成logn段

对于每一段直接在管理节点上面开个vector记录,相当于这是他的子节点共用的

最后遍历整棵树,到达一个点就把它上面的插进线性基,回溯就清空

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<bitset>
#include<vector>
using namespace std;

struct node
{
    int l,r,lc,rc;
    vector< bitset<1100> >s;
    vector<int>clear;
}tr[4100];int trlen,last[510];
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
bitset<1100>lt[1100],t;
void insert(int now,int l,int r,int p)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].s.push_back(lt[p]); 
        return ;
    }
    
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    
         if(r<=mid)  insert(lc,l,r,p);
    else if(mid+1<=l)insert(rc,l,r,p);
    else insert(lc,l,mid,p),insert(rc,mid+1,r,p);
}

void add(int now,int o)//线性基 
{
    for(int i=1;i<=1000;i++)
        if(tr[now].s[o][i])
        {
            if(!lt[i][i])
            {
                lt[i]=tr[now].s[o];
                tr[now].clear.push_back(i);
                break;
            }
            else tr[now].s[o]^=lt[i];
        }
}
void getmax()
{
    t.reset();
    for(int i=1;i<=1000;i++) 
        if(!t[i])t^=lt[i];
    bool flag=false;
    for(int i=1;i<=1000;i++)
    {
        if(t[i]==1)flag=true;
        if(t[i]|flag)
            printf("%d",(t[i]==1));
    }
    if(flag==false)printf("0");
    printf("
");
}
void dfs(int now)
{
    for(int i=0;i<tr[now].s.size();i++)add(now,i);
    
    if(tr[now].l==tr[now].r)getmax();
    else dfs(tr[now].lc),dfs(tr[now].rc);
    
    for(int i=0;i<tr[now].clear.size();i++)lt[tr[now].clear[i]].reset();
}

char ss[1100];int sslen;
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int ID,n,m,x,y;
    scanf("%d%d%d",&ID,&n,&m);
    trlen=0;bt(1,m);
    memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%s",&x,&y,ss+1);sslen=strlen(ss+1);
        if(x==y)continue;
        t.reset();
        for(int j=1;j<=sslen;j++)
            t[1000-sslen+j]=(ss[j]==1);
        
        if(last[x]!=0)insert(1,last[x],i-1,x); last[x]=i;
        if(last[y]!=0)insert(1,last[y],i-1,y); last[y]=i;
        lt[x]^=t;
        lt[y]^=t;
    }
    for(int i=1;i<=n;i++)
        if(last[i]!=0&&last[i]<=m)insert(1,last[i],m,i);
            
    for(int i=1;i<=n;i++)lt[i].reset();
    dfs(1);
    
    return 0;
}

 

以上是关于bzoj4644: 经典傻逼题的主要内容,如果未能解决你的问题,请参考以下文章

经典傻逼题

BZOJ 2222: [Cqoi2006]猜数游戏神奇的做法,傻逼题,猜结论

一个傻逼题

Car 的旅行路线——又是傻逼和傻逼题纠缠的故事

BZOJ4870:[SHOI2017]组合数问题——题解

bzoj4896补退选