zoukankan      html  css  js  c++  java
  • #41 最短路(分治+线性基)

      考虑异或最短路应该怎么求。那么这是个WC原题,dfs一遍找到所有有用的环丢进线性基即可,因为每一个环的权值都是可以取到且不对其他部分产生影响的。

      现在给了一棵树,不妨就把他看做原图的dfs树。每增加一条边就是增加了一个环。算出权值后,现在问题变为求一个数和任选一段区间里的数的最大异或值。

      比较暴力的做法是直接建线段树,每次logn*log2v取出区间线性基。这样可以拿50分。

      线性基的合并实在太慢了。考虑能不能离线搞。每次取出跨过区间中点的询问,处理中点左右的后缀前缀线性基,询问时将两边线性基合并。于是就变成logv(logn+logv)了。

      调了半天发现m和n搞反了。

      果然是NOIp模拟。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 300010
    int n,m,q,p[N],deep[N],value[N],ans[N],t=0;
    struct base
    {
        int size,a[31];
        void ins(int x)
        {
            for (register int i=30;~i;i--)
            {
                if (!x) break;
                if (x&(1<<i))
                if (!a[i]) {a[i]=x;size++;break;}
                else x^=a[i];
            }
        }
        base operator +(const base&b) const
        {
            base c;
            if (size>b.size)
            {
                c.size=size;for (int i=0;i<31;i++) c.a[i]=a[i];
                if (size==31) return c;
                for (register int i=30;~i;i--)
                c.ins(b.a[i]);
            }
            else
            {
                c.size=b.size;for (int i=0;i<31;i++) c.a[i]=b.a[i];
                if (b.size==31) return c;
                for (register int i=30;~i;i--)
                c.ins(a[i]);
            }
            return c;
        }
    }pre[N],suf[N];
    struct data{int to,nxt,len;
    }edge[N<<1];
    struct data2{int i,l,r,x; 
    }Q[N],u[N];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
    void dfs(int k,int from)
    {
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from)
        {
            deep[edge[i].to]=deep[k]^edge[i].len;
            dfs(edge[i].to,k);
        }
    }
    int work(int x,base p)
    {
        for (int i=30;~i;i--)
        x=min(x,x^p.a[i]);
        return x;
    }
    void solve(int l,int r,int low,int high)
    {
        if (l>r||low>high) return;
        if (low==high)
        {
            for (int i=l;i<=r;i++) ans[Q[i].i]=min(Q[i].x,Q[i].x^value[low]);
            return;
        }
        int mid=low+high>>1;
        for (int i=mid;i>=low;i--)
        {
            if (i==mid) pre[i]=(base){0,{0}};
            else pre[i]=pre[i+1];
            pre[i].ins(value[i]);
        }
        for (int i=mid+1;i<=high;i++)
        {
            if (i==mid+1) suf[i]=(base){0,{0}};
            else suf[i]=suf[i-1];
            suf[i].ins(value[i]);
        }
        int head=l-1,tail=r+1;
        for (int i=l;i<=r;i++)
        if (Q[i].l<=mid&&Q[i].r>mid) ans[Q[i].i]=work(Q[i].x,pre[Q[i].l]+suf[Q[i].r]);
        else if (Q[i].r<=mid) u[++head]=Q[i];
        else u[--tail]=Q[i];
        for (int i=l;i<=r;i++) Q[i]=u[i];
        solve(l,head,low,mid);
        solve(tail,r,mid+1,high);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),q=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            addedge(x,y,z),addedge(y,x,z);
        }
        dfs(1,1);
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read();
            value[i]=deep[x]^deep[y]^z;
        }
        for (int i=1;i<=q;i++)
        {
            int s=read(),t=read(),l=read(),r=read();
            Q[i].i=i,Q[i].x=deep[s]^deep[t],Q[i].l=l,Q[i].r=r;
        }
        solve(1,q,1,m);
        for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    Re: 求助:5道算法题
    AutoComplete的字典建立和单词查找算法实现
    求教大牛!关于后缀树
    Qt OpenGL教程
    调试宏
    if结合errorlevel使用:判断一个DOS命令执行成功与否
    写给自己,关于对纯技术的追求,以及为了金钱与前途的技术追求
    <转>我对菜鸟成长的看法
    看完电影有感。。。。。
    <转>标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast
  • 原文地址:https://www.cnblogs.com/Gloid/p/9658421.html
Copyright © 2011-2022 走看看