zoukankan      html  css  js  c++  java
  • [SCOI2016]幸运数字

    题解:

    想找到树剖的题写写,然后就找到了这么一题

    树剖+线段树+线性基显然

    分析一下复杂度就上天了 $nlog^2*60^2$

    不过树剖的log我忽略一下。。线性基合并肯定跑不满假设只有60.。

    差不多还可以跑跑

    于是就写了,然后竟然过了

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid ((h+t)>>1)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=2.1e4;
    const int N1=N*4;
    ll v[N];
    int head[N],l,dep[N],dy[N],son[N],dfn[N],cnt,num[N],fa[N];
    int top[N],n,m,q;
    struct re{
        int a,b;
    }e[N*2];
    IL void arr(int x,int y)
    {
        e[++l].a=head[x];
        e[l].b=y;
        head[x]=l;
    }
    void dfs1(int x,int y)
    {
        num[x]=1; dep[x]=dep[y]+1; fa[x]=y;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v!=y)
            { 
              dfs1(v,x); num[x]+=num[v];
              if (num[v]>num[son[x]]) son[x]=v;
            }
        }
    }
    void dfs2(int x,int t,int y)
    {
        top[x]=t; dfn[x]=++cnt; dy[cnt]=x;
        if (son[x]) dfs2(son[x],t,x);
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v!=y&&v!=son[x]) dfs2(v,v,x);
        }
    }
    struct re2{
        ll a[61];
        re2() {me(a);}
    };
    vector<re2> ve;
    struct sgt{
        ll now[N1][61];
        IL re2 hb(ll *x,ll *y)
        {
            re2 ans;
            int cnt1=0,cnt2=0;
            rep(i,0,60) if (x[i]) cnt1++;
            rep(i,0,60) if (y[i]) cnt2++;
            if (cnt1>cnt2) swap(x,y);
            rep(i,0,60) ans.a[i]=y[i];
            rep(i,0,60)
              if (x[i])
              {
                  ll k=x[i];
                dep(j,60,0)
                {
                  if (!k) break;
                  if ((k>>j)&1)
                    if (ans.a[j]) k^=ans.a[j];
                    else
                    {
                        ans.a[j]=k; break;
                    }
                }
              }
            return ans;
        }
        void build(int x,int h,int t)
        {
            if (h==t)
            {
                dep(i,60,0)
                  if ((v[dy[h]]>>i)&1)
                  {
                      now[x][i]=v[dy[h]];
                      break;
                  }
                return;
            }
            build(x*2,h,mid); build(x*2+1,mid+1,t);
            re2 p=hb(now[x*2],now[x*2+1]);
            memcpy(now[x],p.a,sizeof(p.a));
        }
        void query(int x,int h,int t,int h1,int t1)
        {
            if (h1<=h&&t<=t1)
            {
                re2 p; memcpy(p.a,now[x],sizeof(now[x]));
                ve.push_back(p);
                return;
            }
            if (h1<=mid) query(x*2,h,mid,h1,t1);
            if (mid<t1) query(x*2+1,mid+1,t,h1,t1);
        }
        ll query2(int x,int y)
        {
            ve.clear();
            int f1=top[x],f2=top[y];
            while (f1!=f2)
            {
                if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
                query(1,1,n,dfn[f1],dfn[x]);
                x=fa[f1]; f1=top[x];
            }
            if (dep[x]<dep[y]) swap(x,y);
            query(1,1,n,dfn[y],dfn[x]);
            int l=(int)(ve.size())-1;
            re2 p;
            rep(i,0,l) p=hb(p.a,ve[i].a);
            ll now=0;
            dep(i,60,0)
              if (p.a[i]&&!((now>>i)&1))
              {
                  now^=p.a[i];
              }
            return now;
        }
    }S;
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        read(n); read(q);
        rep(i,1,n) read(v[i]);
        rep(i,1,n-1)
        {
            int x,y;
            read(x); read(y);
            arr(x,y); arr(y,x);
        }
        dfs1(1,0); dfs2(1,1,0);
        S.build(1,1,n);
        rep(i,1,q)
        {
            int x,y;
            read(x); read(y);
            wer(S.query2(x,y)); wer2();
        }
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    当然感觉是数据并不强的原因。。

    然而这题用倍增+线性基$nlog^3$的复杂度 也就比树剖快了一倍

    线性基合并可以有点常数优化见我的代码 看下面

    当然这题是有$nlog^2n$的做法的

    既然离线我们利用点分治

    然后把lca等于rt的放在现在计算

    点分治的一个常数优化是对n<=k的时候进行暴力计算

    但这题里效果应该并不明显

    另外上面那个线性基合并写的太菜了。。

    现在的这个比那个少算了100倍???(实测一个线性基循环3e7 一个1e5)

    优化1:为0直接跳

    优化2:从当前位往下

    优化3:维护最低位

    也就是说线性基合并基本没花时间。。 时间在于插入线性基

    然后把插入线性基也这么优化一下

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mep(x,y) memcpy(x,y,sizeof(y))
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int Z,C=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C]=z[Z],--Z);
        }
        IL void wer1() { sr[++C]=' ';}
        IL void wer2() { sr[++C]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;} 
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y) {return x>y?x:y;}
        template<class T>IL T MIN(T x,T y) {return x<y?x:y;}
    };
    using namespace IO;
    const int N=3e5;
    bool vis[N];
    int head[N],l,num[N],f[N],rt,col[N],all,pos[N],jl[N];
    ll now[N][61],p[N][61],ans[N],v[N];
    struct re{
        int a,b,c;
    }e[N*2],a[N];
    vector<re>ve[N];
    IL void arr(int x,int y)
    {
        e[++l].a=head[x];
        e[l].b=y;
        head[x]=l;
    }
    struct re2{
        ll a[61];
        re2() {me(a);}
    };
    int cnt2=0,cnt3=0; 
    IL re2 hb(ll *x,ll *y)
    {
            cnt2++; 
            re2 ans;
            rep(i,0,60)
            {   
              if (y[i]) ans.a[i]=y[i]; else ans.a[i]=x[i];
            }
            int A;
            for(A=0;A<=60;A++) if (!ans.a[A]) break;
            rep(i,0,60)
              if (x[i]&&y[i])
              {
                  ll k=x[i];
                dep(j,i,A)
                {
                    cnt3++;
                    if (!k) break;
                    if ((k>>j)&1)
                    if (ans.a[j]) k^=ans.a[j];
                    else
                    {
                        ans.a[j]=k; break;
                    }
                    if (j==A)
                    {
                        for (;A<=60;A++) if (!ans.a[A]) break;
                    }
                }
              } 
            return ans;
    }
    void fdr(int x,int y)
    {
        num[x]=1; f[x]=0;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v!=y&&!vis[v])
            {
                fdr(v,x); num[x]+=num[v];
                if (num[v]>f[x]) f[x]=num[v]; 
            }
        }
        if (all-num[x]>f[x]) f[x]=all-num[x];
        if (f[x]<f[rt]) rt=x;
    }
    IL void ins(ll *x,ll y,int z,int &k)
    {
        dep(i,z,k)
        {
          if (!y) return;
          if ((y>>i)&1)
            if (x[i]) y^=x[i]; else
            {
                x[i]=y; break;
            }
        }
        while (x[k]) k++;
    }
    void dfs(int x,int y,int color)
    {
        mep(p[x],p[y]); jl[x]=jl[y];
        ins(p[x],v[x],pos[x],jl[x]);
        col[x]=color;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v!=y&&!vis[v]) dfs(v,x,color);
        }
    }
    int cnt=0;
    void dfz(int x,int y)
    {
        all=num[x]; rt=0; f[x]=0; fdr(x,0);
        mep(p[rt],now[rt]); jl[rt]=0;
        for(rint u=head[rt];u;u=e[u].a)
        {
            int v=e[u].b;
            if (!vis[v]) dfs(v,rt,++cnt);
        }
        int l=(int)(ve[y].size())-1;
        rep(i,0,l)
        {
          int x1=ve[y][i].a,x2=ve[y][i].b;
          if (col[x1]!=col[x2]||x1==rt)
          {
              re2 o=hb(p[x1],p[x2]);
              ll now=0;
            dep(i,60,0)
              if (o.a[i]&&!((now>>i)&1))
              {
                  now^=o.a[i];
              }
            ans[ve[y][i].c]=now;
          } else ve[col[x1]].push_back(ve[y][i]);
        }
        vis[rt]=1;
        for (rint u=head[rt];u;u=e[u].a)
        {
            int v=e[u].b;
            if (!vis[v]) dfz(v,col[v]);
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        f[0]=1e9; 
        int n,m;
        read(n); read(m);
        rep(i,1,n)
        { 
          read(v[i]);
          dep(j,60,0)
            if ((v[i]>>j)&1)
            {
                now[i][j]=v[i]; pos[i]=j; break;
            }
        }
        rep(i,1,n-1)
        {
            int x,y;
            read(x); read(y);
            arr(x,y); arr(y,x); 
        }
        rep(i,1,m)
        { 
          read(a[i].a),read(a[i].b),a[i].c=i;
          ve[1].push_back(a[i]); 
        }
        num[1]=n; 
        cnt=1; dfz(1,1);
        rep(i,1,m) wer(ans[i]),wer2();
        fwrite(sr,1,C+1,stdout);
        return 0;
    }
  • 相关阅读:
    常用基础命令
    Vim
    Linux目录结构
    稀疏数组
    数据结构概述
    天天用的命令
    Mysql和redis的安装
    回文排列
    URL化
    在word中做复选框打对勾钩
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10103879.html
Copyright © 2011-2022 走看看