LOJ 2013 幸运数字

题意: https://loj.ac/problem/2013

sol:

用点分治每次处理lca在分治重心上的询问,对于每个询问都单独开个表挂在其中一个点上

树剖和倍增都是3个log,需要卡常(其实是复杂度不对),点分治处理路径是\(\log w \log n\),然后每个点上的询问会被搞q次

如果回答询问的话是\(\log w^2\)的复杂度,总复杂度\(n \log n\log w+q\log w^2\)

点分代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
const int N = 2e4+7;
typedef long long LL;
#define R register
#define debug printf("GG\n")
#define cer(x) printf("%d\n", x)
int last[N], cnt;
std :: vector<int> G[N], Q[N];
inline int max(int a, int b) {
  return a > b ? a : b;
}
struct Edge {
  int to, nxt;
} e[N*2];
inline void add(int u, int v) {
  e[++cnt].nxt = last[u], e[cnt].to = v, last[u] = cnt;
}
LL pw[N];
struct Ask {
  int x, y;
  LL ans;
} q[N*10];
struct LB {
  LL d[62];
  inline void ins(LL x) {
    for (R int i = 60; i >= 0; i--) if ((x >> i) & 1) {
      if (!d[i]) {
        d[i] = x;
        break;
      } else x ^= d[i];
    }
  }
  inline LL query() {
    LL res = 0;
    for (R int i = 60; i >= 0; i--)
      ((res ^ d[i]) > res) ? res ^= d[i] : 0;
    return res;
  }
  void clear() {
    memset(d, 0, sizeof(d));
  }
};
LB B[N];
int siz[N], rt, SIZ, vis[N], mxson[N];
void findrt(int x, int fa) {
  siz[x] = 1, mxson[x] = 0;
  //cer(x);
  for (int o = last[x]; o; o = e[o].nxt) {
    int to = e[o].to;
    if (to == fa || vis[to]) continue;
    findrt(to, x), siz[x] += siz[to], mxson[x] = max(mxson[x], siz[to]);
  }
  mxson[x] = max(mxson[x], SIZ - siz[x]);
  mxson[x] < mxson[rt] ? rt = x : 0;
  //debug;
}
int vis2[N], q1[N], tail, front, solved[N*10], col[N];
void findp(int x, int fa, int color) {
  //if (!fa && B[fa].query() > 0) debug;
  B[x] = B[fa], B[x].ins(pw[x]), vis2[x] = 1;
  q1[tail++] = x, col[x] = color;
  //cer(x);
  for (R int o = last[x]; o; o = e[o].nxt) {
    int to = e[o].to;
    if (to == fa || vis[to]) continue;
    findp(to, x, !fa ? ++color : color);
  }
}
int q2[N], t2, f2;
void getans(int x) {
  tail = front = t2 = f2 = 0; findp(x, 0, 0);
  while (front < tail) {
    int nx = q1[front++], size = G[nx].size();
    for (R int o = 0; o < size; o++) 
      if (vis2[G[nx][o]] && !solved[Q[nx][o]] && (col[nx] != col[G[nx][o]] || (nx == x && G[nx][o] == x))) {
        LB res = B[nx];
        for (R int i = 60; i >= 0; i--) 
          if (B[G[nx][o]].d[i] > 0) res.ins(B[G[nx][o]].d[i]);
        solved[Q[nx][o]] = 1;
        q[Q[nx][o]].ans = res.query();
        //if (x == 1) cer(B[nx].query());
      }
    q2[t2++] = nx;
  }
  while (f2 < t2) {
    B[q2[f2]].clear(); vis2[q2[f2]] = col[q2[f2]] = 0; f2++;
  } B[0].clear();
}
void divrt(int x) {
  vis[x] = 1; getans(x);
  for (R int o = last[x]; o; o = e[o].nxt) {
    int to = e[o].to;
    if (vis[to]) continue;
    rt = 0, SIZ = siz[to], findrt(to, x), divrt(rt);
  }
}
int n, qq;
int main() {
  //freopen("pick.in", "r", stdin);
  //freopen("pick_check.out", "w", stdout);
  scanf("%d%d", &n, &qq);
  for (R int i = 1; i <= n; i++)
    scanf("%lld", &pw[i]);
  for (R int i = 1, x, y; i < n; i++)
    scanf("%d%d", &x, &y), add(x, y), add(y, x);
  for (R int i = 1; i <= qq; i++) 
    scanf("%d%d", &q[i].x, &q[i].y), G[q[i].x].push_back(q[i].y), Q[q[i].x].push_back(i);
  siz[0] = mxson[0] = SIZ = n, rt = 0;
  findrt(1, 0), divrt(rt);
  //cer(rt);
  for (R int i = 1; i <= qq; i++)
    printf("%lld\n", q[i].ans);
return 0;
}

树剖代码:

卡过去其实挺简单?在线性基里维护一个minmax然后扫的时候只扫minmax就好了大概常数能减小一半

#include<cstdio>
#include<iostream>
#include<cstring>
#define R register
#define debug printf("GG\n")
const int N = 2e5+7;
typedef long long LL; 
int last[N], cnt;
struct Edge {int to, nxt;} e[N*2];
int n, q; LL val[N];
inline int min(R int a, R int b) {
  return b > a ? a : b;
}
inline int max(R int a, R int b) {
  return a > b ? a : b;
}
inline void add(R int u, R int v) {
  e[++cnt].nxt = last[u], e[cnt].to = v, last[u] = cnt;
}
struct LB {
  LL d[61]; int Last, Start;
  inline void Modify(R LL x) {
    for (R int i = 60; i >= 0; i--)
      if ((x >> i) & 1LL) {
        if (!d[i]) {
          d[i] = x;
          Start = max(Start, i);
          Last = min(Last, i);
          break;
          
        }
        else x ^= d[i];
      } else if (!x) break;
  }
  inline void clear() {
    memset(d, 0, sizeof(d));
  }
};
struct Graph {
  int dep, fa, siz, son, top;
  LL w;
} G[N];
void dfs1(int x, int fa, int dep) {
  G[x].siz = 1, G[x].dep = dep, G[x].fa = fa;
  G[x].w = val[x];
 // if (x == 2)
 //   printf("%d %d %d\n", x, G[x].dep, G[x].fa);
  int max_son = -1;
  for (int o = last[x]; o > 0; o = e[o].nxt) {
    //debug;
    //printf("%d %d\n", o, e[o].to);
    int to = e[o].to;
    //printf("%d ", to);
//    if (to == 2)
  //    printf("%d %d %d\n", x, G[x].dep, G[x].fa);
    if (to == fa) continue;
    dfs1(to, x, dep + 1);
    G[x].siz += G[to].siz;
    if (G[to].siz > max_son) 
      max_son = G[to].siz, G[x].son = to;
  }
}
int idx[N];LL A[N];
void dfs2(int x, int top) {
  G[x].top = top, idx[x] = ++cnt, A[cnt] = G[x].w;
  if (!G[x].son) return;
  dfs2(G[x].son, top);
  for (int o = last[x]; o > 0; o = e[o].nxt) {
    int to = e[o].to;
    //debug;
    if (to == G[x].fa || to == G[x].son) continue;
    dfs2(to, to);
  }
}
struct segT {
  int lc, rc; LB omg;
} t[N*2];
inline void pushup(R int u) {
  LB A = t[t[u].lc].omg, B = t[t[u].rc].omg;
  for (R int i = B.Start; i >= B.Last; i--) 
    if (B.d[i] > 0) A.Modify(B.d[i]);
  t[u].omg = A;
}
void build(int u, int l, int r) {
  //int MID = (l + r) >> 1;
  if (l == r) {
    t[u].omg.Modify(A[l]); return;
  }
  int MID = (l + r) >> 1;
  build(t[u].lc = ++cnt, l, MID),
  build(t[u].rc = ++cnt, MID + 1, r);
  pushup(u);
}
LB res;
void query(int u, int l, int r, int sl, int sr) {
  if (sl == l && sr == r) {
    LB A = t[u].omg;
    for (R int i = A.Start; i >= A.Last; i--)
      if (A.d[i] > 0) res.Modify(A.d[i]);//, printf("%d %d %d\n", i, A.d[i], l);
    return;
  }
  int MID = (l + r) >> 1;
  if (sr <= MID) query(t[u].lc, l, MID, sl, sr);
  else if (sl > MID) query(t[u].rc, MID + 1, r, sl, sr);
  else query(t[u].lc, l, MID, sl, MID), query(t[u].rc, MID + 1, r, MID + 1, sr);
}
inline LL ASK(R int x, R int y) {
  //LB ans; ans.clear();
  //debug;
  res.clear();
  while (G[x].top != G[y].top) {
    //res.clear();
   // printf("%d %d %d %d\n", x, G[x].top, y, G[y].top);
    if (G[G[x].top].dep < G[G[y].top].dep) 
      std :: swap(x, y);
    query(1, 1, n, idx[G[x].top], idx[x]);
    x = G[G[x].top].fa;
  //  for (int i = 60; i >= 0; i--)
  //    if (res.d[i] > 0) ans.Modify(res.d[i]);
  }
  if (G[x].dep < G[y].dep) std :: swap(x, y);
  //res.clear();
  query(1, 1, n, idx[y], idx[x]);
  //for (int i = 60; i >= 0; i--) 
  //  if (res.d[i] > 0) ans.Modify(res.d[i]);
  R LL ii = 0LL;
  for (R int i = res.Start; i >= res.Last; i--)
    if (res.d[i] > 0)
      ii = (ii ^ res.d[i]) > ii ? (ii ^ res.d[i]) : ii;
  return ii;
}
int main() {
  scanf("%d%d", &n, &q);
  for (R int i = 1; i <= n; i++)
    scanf("%lld", &val[i]);
  for (R int i = 1, ox, oy; i < n; i++) {
    R int x, y;
    scanf("%d%d", &x, &y), add(x, y), add(y, x);
  }
  //for (int i = 1; i <= 2 * n - 2; i++)
  //  printf("last : %d to : %d nxt : %d x : %d\n", last[i], e[i].to, e[i].nxt, i);
  dfs1(1, 1, 1), cnt = 0, dfs2(1, 1), cnt = 1, build(1, 1, n);
  while (q--) {
    R int x, y;
    scanf("%d%d", &x, &y);
    printf("%lld\n", ASK(x, y));
  }
}

posted @ 2019-10-08 21:38  ComeIntoCalm  阅读(...)  评论(...编辑  收藏