码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4644: 经典傻逼题

时间:2018-12-29 17:14:43      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:a.out   res   back   eof   ret   str   时间轴   sizeof   names   

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

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

但是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("\n");
}
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: 经典傻逼题

标签:a.out   res   back   eof   ret   str   时间轴   sizeof   names   

原文地址:https://www.cnblogs.com/AKCqhzdy/p/10196492.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!