CF1101

D:题意:树上每个顶点有个权值,求最长链,满足链上gcd > 1

解:对每个质数建虚树,每个点只会拆成log个点,所以是log2的。

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 200010;
  4 
  5 struct Edge {
  6     int nex, v, len;
  7 }edge[N << 1], EDGE[N << 1]; int tp, TP;
  8 
  9 int p[N], top, e[N], pos2[N], num2, ST[N << 1][20], pw[N << 2], n, ans, id[N], last[N];
 10 int vis[N];
 11 int imp[N], K, E[N], val[N], fa[N], d[N], stk[N], use[N], Time, RT, f[N];
 12 std::vector<int> v[N];
 13 
 14 inline void add(int x, int y) {
 15     tp++;
 16     edge[tp].v = y;
 17     edge[tp].nex = e[x];
 18     e[x] = tp;
 19     return;
 20 }
 21 
 22 inline void ADD(int x, int y) {
 23     TP++;
 24     EDGE[TP].v = y;
 25     EDGE[TP].len = d[y] - d[x];
 26     EDGE[TP].nex = E[x];
 27     E[x] = TP;
 28     return;
 29 }
 30 
 31 inline void getp(int n) {
 32     for(int i = 2; i <= n; i++) {
 33         if(!vis[i]) {
 34             p[++top] = i;
 35             last[i] = i;
 36             id[i] = top;
 37         }
 38         for(int j = 1; j <= top && i * p[j] <= n; j++) {
 39             vis[i * p[j]] = 1;
 40             last[i * p[j]] = p[j];
 41             if(i % p[j] == 0) break;
 42         }
 43     }
 44     return;
 45 }
 46 
 47 void DFS_1(int x, int f) {
 48     fa[x] = f;
 49     d[x] = d[f] + 1;
 50     pos2[x] = ++num2;
 51     ST[num2][0] = x;
 52     for(int i = e[x]; i; i = edge[i].nex) {
 53         int y = edge[i].v;
 54         if(y == f) {
 55             continue;
 56         }
 57         DFS_1(y, x);
 58         ST[++num2][0] = x;
 59     }
 60     return;
 61 }
 62 
 63 inline void prework() {
 64     for(int i = 2; i <= num2; i++) pw[i] = pw[i >> 1] + 1;
 65     for(int j = 1; j <= pw[num2]; j++) {
 66         for(int i = 1; i + (1 << j) - 1 <= num2; i++) {
 67             if(d[ST[i][j - 1]] < d[ST[i + (1 << (j - 1))][j - 1]])
 68                 ST[i][j] = ST[i][j - 1];
 69             else
 70                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
 71         }
 72     }
 73     return;
 74 }
 75 
 76 inline int lca(int x, int y) {
 77     x = pos2[x];
 78     y = pos2[y];
 79     if(x > y) std::swap(x, y);
 80     int t = pw[y - x + 1];
 81     if(d[ST[x][t]] < d[ST[y - (1 << t) + 1][t]])
 82         return ST[x][t];
 83     else
 84         return ST[y - (1 << t) + 1][t];
 85 }
 86 
 87 inline bool cmp(const int &a, const int &b) {
 88     return pos2[a] < pos2[b];
 89 }
 90 
 91 inline void work(int x) {
 92     if(use[x] != Time) {
 93         use[x] = Time;
 94         f[x] = 0;
 95         E[x] = 0;
 96     }
 97     return;
 98 }
 99 
100 inline void build_t() {
101     std::sort(imp + 1, imp + K + 1, cmp);
102     TP = top = 0;
103     work(imp[1]);
104     stk[++top] = imp[1];
105     for(int i = 2; i <= K; i++) {
106         int x = imp[i], y = lca(x, stk[top]);
107         work(x); work(y);
108         while(top > 1 && pos2[y] <= pos2[stk[top - 1]]) {
109             ADD(stk[top - 1], stk[top]);
110             top--;
111         }
112         if(y != stk[top]) {
113             ADD(y, stk[top]);
114             stk[top] = y;
115         }
116         stk[++top] = x;
117     }
118     while(top > 1) {
119         ADD(stk[top - 1], stk[top]);
120         top--;
121     }
122     RT = stk[top];
123     return;
124 }
125 
126 void DFS(int x) {
127     int a = 0, b = 0;
128     for(int i = E[x]; i; i = EDGE[i].nex) {
129         int y = EDGE[i].v;
130         DFS(y);
131         if(EDGE[i].len > 1) continue;
132         if(f[y] > a) {
133             b = a;
134             a = f[y];
135         }
136         else b = std::max(b, f[y]);
137     }
138     if(vis[x] == Time) {
139         ans = std::max(ans, a + b + 1);
140         f[x] = a + 1;
141     }
142     return;
143 }
144 
145 int main() {
146     getp(N - 1);
147     memset(vis, 0, sizeof(vis));
148     int tot = top, flag = 1;
149 
150     scanf("%d", &n);
151     for(int i = 1; i <= n; i++) {
152         scanf("%d", &val[i]);
153         int x = val[i];
154         if(x > 1) flag = 0;
155         while(x > 1) {
156             int y = last[x];
157             while(x % y == 0) {
158                 x /= y;
159             }
160             v[id[y]].push_back(i);
161         }
162     }
163     for(int i = 1, x, y; i < n; i++) {
164         scanf("%d%d", &x, &y);
165         add(x, y); add(y, x);
166     }
167 
168     if(flag) {
169         puts("0");
170         return 0;
171     }
172 
173     DFS_1(1, 0);
174     prework();
175 
176     for(int i = 1; i <= tot; i++) {
177         K = 0;
178         ++Time;
179         for(int j = 0; j < (int)v[i].size(); j++) {
180             imp[++K] = v[i][j];
181             vis[v[i][j]] = Time;
182         }
183         build_t();
184         DFS(RT);
185     }
186 
187     printf("%d 
", ans);
188     return 0;
189 }
AC代码

G:题意:给定序列,你要把它分成尽可能多的几段,每段的权值是异或和。

要求没有哪些段的权值异或和为0。输出最大段数。无解-1。

解:考虑无解,肯定是总异或和为0。否则一定存在解。

发现这个东西,其实等价于选出一些前缀,因为异或可以抵消,所以这些前缀能表示出的和这些段能表示出的是相同的。

然后就把前缀插入线性基,看能插入多少个。

看到异或就要想线性基。

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 200010;
 4 
 5 int b[32], a[N];
 6 
 7 inline int insert(int x) {
 8     for(int i = 30; i >= 0 && x; i--) {
 9         if(((x >> i) & 1) == 0) continue;
10         if(b[i]) x ^= b[i];
11         else {
12             b[i] = x;
13             return 1;
14         }
15     }
16     return 0;
17 }
18 
19 int main() {
20 
21     int n;
22     scanf("%d", &n);
23     for(int i = 1; i <= n; i++) {
24         scanf("%d", &a[i]);
25         a[i] ^= a[i - 1];
26     }
27 
28     if(!a[n]) {
29         printf("-1
");
30         return 0;
31     }
32 
33     int cnt = 0;
34     for(int i = n; i >= 1; i--) {
35         cnt += insert(a[i]);
36     }
37 
38     printf("%d 
", cnt);
39     return 0;
40 }
AC代码
原文地址:https://www.cnblogs.com/huyufeifei/p/10600383.html