这周看了半天后缀自动机没看懂,看了半天多项式又没看懂,wtnl
[SDOI2008]洞穴勘测:LCT
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e4 + 50;
int n,m,x,y,top,fa[maxn],son[maxn][2],s[maxn],r[maxn];
char type;
bool nroot(int u){
return son[fa[u]][0] == u || son[fa[u]][1] == u;
}
void push_down(int u){
if(r[u]){
swap(son[u][0],son[u][1]);
r[son[u][0]] ^= 1,r[son[u][1]] ^= 1;
r[u] = 0;
}
}
void rotate(int u){
int v = fa[u],d = (son[v][1] == u);
if(nroot(v)) son[fa[v]][son[fa[v]][1] == v] = u;
son[v][d] = son[u][d ^ 1],son[u][d ^ 1] = v;
fa[u] = fa[v],fa[v] = u,fa[son[v][d]] = v;
}
void splay(int u){
int t = u;
s[++top] = t;
while(nroot(t)) t = fa[t],s[++top] = t;
while(top) push_down(s[top]),top --;
while(nroot(u)){
int f = fa[u];
if(!nroot(f)){
rotate(u);
break;
}
if((son[fa[f]][1] == f) == (son[f][1] == u)) rotate(f),rotate(u);
else rotate(u),rotate(u);
}
}
void access(int u){
int last = 0;
while(u){
splay(u);
son[u][1] = last,last = u,u = fa[u];
}
}
void change_root(int u){
access(u);
splay(u);
r[u] = 1;
}
int root(int u){
access(u);
splay(u);
while(son[u][0]) push_down(u),u = son[u][0];
return u;
}
void split(int u,int v){
change_root(u);
access(v);
splay(v);
}
void link(int u,int v){
change_root(u);
access(v);
splay(v);
fa[u] = v;
}
void cut(int u,int v){
split(u,v);
fa[u] = 0,son[v][0] = 0;
}
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
int main(){
n = read(),m = read();
for(int i = 1; i <= m; i ++){
getchar();
type = getchar();
x = read(),y = read();
if(type == 'C') link(x,y);
else if(type == 'D') cut(x,y);
else{
if(root(x) == root(y)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
[ZJOI2012]网络:LCT
由于 C ⩽ 10 C \leqslant 10 C⩽10,容易想到对每种颜色分别建LCT,但在每个函数、变量前加一个参数十分不美观且容易出错,可以将LCT封装起来
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e4 + 50,maxc = 12;
int n,m,C,k,x,y,c,type,val[maxn],num[maxn][maxc];
struct Link_Cut_Tree{
int top,s[maxn],r[maxn],maxv[maxn],fa[maxn],son[maxn][2];
bool nroot(int u){
return son[fa[u]][0] == u || son[fa[u]][1] == u;
}
void update(int u){
maxv[u] = max(val[u],max(maxv[son[u][0]],maxv[son[u][1]]));
}
void push_down(int u){
if(r[u]){
swap(son[u][0],son[u][1]);
r[son[u][0]] ^= 1,r[son[u][1]] ^= 1;
r[u] = 0;
}
}
void rotate(int u){
int v = fa[u],d = (son[v][1] == u);
if(nroot(v)) son[fa[v]][son[fa[v]][1] == v] = u;
son[v][d] = son[u][d ^ 1],son[u][d ^ 1] = v;
fa[u] = fa[v],fa[v] = u,fa[son[v][d]] = v;
update(v),update(u);
}
void splay(int u){
int t = u;
s[++top] = t;
while(nroot(t)) t = fa[t],s[++top] = t;
while(top) push_down(s[top]),top --;
while(nroot(u)){
int f = fa[u];
if(!nroot(f)){
rotate(u);
break;
}
if((son[fa[f]][1] == f) == (son[f][1] == u)) rotate(f),rotate(u);
else rotate(u),rotate(u);
}
}
void access(int u){
int last = 0;
while(u){
splay(u);
son[u][1] = last;
update(u);
last = u,u = fa[u];
}
}
void change_root(int u){
access(u);
splay(u);
r[u] = 1;
}
int root(int u){
access(u);
splay(u);
while(son[u][0]) push_down(u),u = son[u][0];
return u;
}
void split(int u,int v){
change_root(u);
access(v);
splay(v);
}
void link(int u,int v){
change_root(u);
access(v);
splay(v);
fa[u] = v;
}
void cut(int u,int v){
split(u,v);
fa[u] = 0,son[v][0] = 0;
update(v);
}
}a[maxc];
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
int main(){
n = read(),m = read(),C = read(),k = read();
for(int i = 1; i <= n; i ++) val[i] = read();
for(int i = 1; i <= m; i ++){
x = read(),y = read(),c = read();
num[x][c] ++,num[y][c] ++;
a[c].link(x,y);
}
while(k --){
type = read();
if(type == 0){
x = read(),y = read();
val[x] = y;
for(int i = 0; i < C; i ++) a[i].splay(x);
}else if(type == 1){
x = read(),y = read(),c = read();
for(int i = 0; i < C; i ++){
if(a[i].root(x) == a[i].root(y)){
a[i].split(x,y);
if(a[i].son[y][0] != x || a[i].son[x][1]) continue;
if(i == c) printf("Success.\n");
else if(num[x][c] == 2 || num[y][c] == 2) printf("Error 1.\n");
else if(a[c].root(x) == a[c].root(y)) printf("Error 2.\n");
else{
num[x][i] --,num[y][i] --;
a[i].cut(x,y);
num[x][c] ++,num[y][c] ++;
a[c].link(x,y);
printf("Success.\n");
}
goto end;
}
}
printf("No such edge.\n");
}else{
c = read(),x = read(),y = read();
if(a[c].root(x) != a[c].root(y)) printf("-1\n");
else{
a[c].split(x,y);
printf("%d\n",a[c].maxv[y]);
}
}
end: ;
}
return 0;
}
[HNOI2010]弹飞绵羊:LCT
感觉这题的LCT被阉割了很多,可能可以用别的东西维护?
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 2e5 + 50;
int n,m,x,y,type,top,a[maxn],size[maxn],r[maxn],fa[maxn],sta[maxn],son[maxn][2];
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
bool nroot(int u){
return son[fa[u]][0] == u || son[fa[u]][1] == u;
}
void update(int u){
size[u] = size[son[u][0]] + size[son[u][1]] + 1;
}
void push_down(int u){
if(r[u]){
swap(son[u][0],son[u][1]);
r[son[u][0]] ^= 1,r[son[u][1]] ^= 1;
r[u] = 0;
}
}
void rotate(int u){
int v = fa[u],d = (son[v][1] == u);
if(nroot(v)) son[fa[v]][son[fa[v]][1] == v] = u;
son[v][d] = son[u][d ^ 1],son[u][d ^ 1] = v;
fa[u] = fa[v],fa[v] = u,fa[son[v][d]] = v;
update(v),update(u);
}
void splay(int u){
int t = u;
sta[++top] = t;
while(nroot(t)) t = fa[t],sta[++top] = t;
while(top) push_down(sta[top]),top --;
while(nroot(u)){
int f = fa[u];
if(!nroot(f)){
rotate(u);
break;
}
if((son[fa[f]][1] == f) == (son[f][1] == u)) rotate(f),rotate(u);
else rotate(u),rotate(u);
}
}
void access(int u){
int last = 0;
while(u){
splay(u);
son[u][1] = last;
update(u);
last = u,u = fa[u];
}
}
void change_root(int u){
access(u);
splay(u);
r[u] ^= 1;
}
int root(int u){
access(u);
splay(u);
while(son[u][0]) push_down(u),u = son[u][0];
return u;
}
void split(int u,int v){
change_root(u);
access(v);
splay(v);
}
void link(int u,int v){
change_root(u);
fa[u] = v;
}
void cut(int u,int v){
split(u,v);
fa[u] = 0,son[v][0] = 0;
update(v);
}
int main(){
n = read();
for(int i = 1; i <= n; i ++) a[i] = read(),link(i,min(n + 1,i + a[i]));
m = read();
for(int i = 1; i <= m; i ++){
type = read();
if(type == 1){
x = read() + 1;
split(x,n + 1);
printf("%d\n",size[n + 1] - 1);
}else{
x = read() + 1,y = read();
cut(x,min(n + 1,x + a[x]));
a[x] = y;
link(x,min(n + 1,x + a[x]));
}
}
return 0;
}
[USACO07DEC]Best Cow Line G:后缀数组
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 5e5 + 50,maxm = 2 * maxn;
int n,m,cnt,x1[maxm],x2[maxm],bk[maxm],sa[maxm],t[maxm],rk[maxm];
char s[maxm],ans[maxn];
void SA(){
int mx = 27;
for(int i = 1; i <= m; i ++) x1[i] = s[i] - 'A' + 1,bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = m; i >= 1; i --) sa[bk[x1[i]] --] = i;
for(int k = 1; k <= m; k <<= 1){
cnt = 0;
for(int i = m - k + 1; i <= m; i ++) x2[++cnt] = i;
for(int i = 1; i <= m; i ++) if(sa[i] > k) x2[++cnt] = sa[i] - k;
for(int i = 1; i <= mx; i ++) bk[i] = 0;
for(int i = 1; i <= m; i ++) bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = m; i >= 1; i --) sa[bk[x1[x2[i]]] --] = x2[i];
for(int i = 1; i <= m; i ++) t[i] = x1[i];
cnt = 0;
for(int i = 1; i <= m; i ++){
if(t[sa[i]] != t[sa[i - 1]] || t[sa[i] + k] != t[sa[i - 1] + k]) cnt ++;
x1[sa[i]] = cnt;
}
if(cnt == m) break;
else mx = cnt;
}
for(int i = 1; i <= m; i ++) rk[sa[i]] = i;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i ++) getchar(),s[i] = s[2 * n - i + 2] = getchar();
s[n + 1] = 'Z' + 1;
// for(int i = 1; i <= n; i ++) cout << s[i] << endl;
m = 2 * n + 1;
SA();
cnt = 0;
int l = 1,r = n;
while(l < r){
if(s[l] < s[r]) ans[++cnt] = s[l],l ++;
else if(s[r] > s[l]) ans[++cnt] = s[r],r --;
else{
if(rk[l] < rk[2 * n - r + 2]) ans[++cnt] = s[l],l ++;
else ans[++cnt] = s[r],r --;
}
}
ans[++cnt] = s[l];
for(int i = 1; i <= n; i ++){
printf("%c",ans[i]);
if(i % 80 == 0) printf("\n");
}
return 0;
}
[JSOI2007]字符加密: 后缀数组
纠结了好久为啥不能直接STL排序,好久才发现卡空间,tcl
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 50;
int n,m,mx,cnt,t[maxn],bk[maxn],x1[maxn],x2[maxn],sa[maxn];
string s;
void SA(){
mx = 122;
for(int i = 1; i <= m; i ++) x1[i] = s[i],bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = m; i >= 1; i --) sa[bk[x1[i]] --] = i;
for(int k = 1; k <= m; k <<= 1){
cnt = 0;
for(int i = m - k + 1; i <= m; i ++) x2[++cnt] = i;
for(int i = 1; i <= m; i ++) if(sa[i] > k) x2[++cnt] = sa[i] - k;
for(int i = 1; i <= mx; i ++) bk[i] = 0;
for(int i = 1; i <= m; i ++) bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = m; i >= 1; i --) sa[bk[x1[x2[i]]] --] = x2[i];
for(int i = 1; i <= m; i ++) t[i] = x1[i];
cnt = 0;
for(int i = 1; i <= m; i ++){
if(t[sa[i]] == t[sa[i - 1]] && t[sa[i] + k] == t[sa[i - 1] + k]) x1[sa[i]] = cnt;
else x1[sa[i]] = ++cnt;
}
if(cnt == m) break;
mx = cnt;
}
}
int main(){
cin >> s;
n = s.size(),m = 2 * n,s += s;
SA();
for(int i = 1; i <= m; i ++) if(sa[i] <= n) printf("%c",s[sa[i] + n - 1]);
return 0;
}
[USACO06DEC]Milk Patterns G:后缀数组,LCP,RMQ
结论仍然不会证系列
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 2e4 + 50,maxnum = 1e6 + 50,inf = 1e9;
int n,k,mx,cnt,ans,a[maxn],t[maxn],bk[maxnum],x1[maxn],x2[maxn],sa[maxn],rk[maxn],h[maxn],Log[maxn],f[maxn][20];
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
void get_SA(){
for(int i = 1; i <= n; i ++) x1[i] = a[i],bk[x1[i]] ++,mx = max(mx,x1[i]);
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = n; i >= 1; i --) sa[bk[x1[i]] --] = i;
for(int k = 1; k <= n; k <<= 1){
cnt = 0;
for(int i = n - k + 1; i <= n; i ++) x2[++cnt] = i;
for(int i = 1; i <= n; i ++) if(sa[i] > k) x2[++cnt] = sa[i] - k;
for(int i = 1; i <= mx; i ++) bk[i] = 0;
for(int i = 1; i <= n; i ++) bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = n; i >= 1; i --) sa[bk[x1[x2[i]]] --] = x2[i];
for(int i = 1; i <= n; i ++) t[i] = x1[i];
cnt = 0;
for(int i = 1; i <= n; i ++){
if(t[sa[i]] != t[sa[i - 1]] || t[sa[i] + k] != t[sa[i - 1] + k]) ++cnt;
x1[sa[i]] = cnt;
}
if(cnt == n) break;
mx = cnt;
}
}
void get_height(){
for(int i = 1; i <= n; i ++) rk[sa[i]] = i;
int p = 0;
for(int i = 1; i <= n; i ++){
if(rk[i] == 1) continue;
if(p) p --;
int t = sa[rk[i] - 1];
while(i + p <= n && t + p <= n && a[i + p] == a[t + p]) p ++;
h[rk[i]] = p;
}
}
void init(){
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= 15; j ++)
f[i][j] = inf;
for(int i = 1; i <= n; i ++) f[i][0] = h[i],Log[i] = (i == 1) ? 0 : Log[i >> 1] + 1;
for(int i = n; i >= 1; i --)
for(int j = 1; i + (1 << (j - 1)) <= n; j ++)
f[i][j] = min(f[i][j - 1],f[i + (1 << (j - 1))][j - 1]);
}
int query(int l,int r){
int t = Log[r - l + 1];
return min(f[l][t],f[r - (1 << t) + 1][t]);
}
int main(){
n = read(),k = read();
for(int i = 1; i <= n; i ++) a[i] = read();
get_SA();
get_height();
init();
for(int i = 1; i <= n - k + 2; i ++) ans = max(ans,query(i,i + k - 2));
cout << ans << endl;
return 0;
}
[HAOI2016]找相同字符:后缀数组,LCP,单调栈
#include <iostream>
using namespace std;
const int maxn = 4e5 + 50;
int t[maxn],bk[maxn],x1[maxn],x2[maxn],sa[maxn],rk[maxn],h[maxn],sta[maxn],l[maxn],r[maxn];
string s1,s2;
void get_SA(string s){
int len = s.size(),mx = 0,cnt = 0;
for(int i = 1; i <= 'z' + 1; i ++) bk[i] = 0;
for(int i = 1; i <= len; i ++) x1[i] = s[i - 1],bk[x1[i]] ++,mx = max(mx,x1[i]);
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = len; i >= 1; i --) sa[bk[x1[i]] --] = i;
for(int k = 1; k <= len; k <<= 1){
cnt = 0;
for(int i = len - k + 1; i <= len; i ++) x2[++cnt] = i;
for(int i = 1; i <= len; i ++) if(sa[i] > k) x2[++cnt] = sa[i] - k;
for(int i = 1; i <= mx; i ++) bk[i] = 0;
for(int i = 1; i <= len; i ++) bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = len; i >= 1; i --) sa[bk[x1[x2[i]]] --] = x2[i];
for(int i = 1; i <= len; i ++) t[i] = x1[i];
cnt = 0;
for(int i = 1; i <= len; i ++){
if(t[sa[i]] == t[sa[i - 1]] && t[sa[i] + k] == t[sa[i - 1] + k]) x1[sa[i]] = cnt;
else x1[sa[i]] = ++cnt;
}
if(cnt == len) break;
else mx = cnt;
}
}
void get_height(string s){
int len = s.size();
for(int i = 1; i <= len; i ++) rk[sa[i]] = i;
int p = 0;
for(int i = 1; i <= len; i ++){
if(rk[i] == 1) continue;
if(p) p --;
int t = sa[rk[i] - 1];
while(i + p <= len && t + p <= len && s[i + p - 1] == s[t + p - 1]) p ++;
h[rk[i]] = p;
}
}
long long sum(string s){
get_SA(s);
get_height(s);
int len = s.size(),top = 0,p = 0;
long long sum = 0;
// for(int i = 1; i <= len; i ++) cout << h[i] << ' ';
// cout << endl;
sta[0] = 1;
for(int i = 2; i <= len; i ++){
if(s[sa[i] - 1] == 'z' + 1){
p = i;
continue;
}
while(top && h[sta[top]] >= h[i]) top --;
l[i] = i - sta[top] - (sta[top] < p),sta[++top] = i;
}
top = 0,sta[0] = len + 1,p = len + 1;
for(int i = len; i >= 2; i --){
if(s[sa[i] - 1] == 'z' + 1){
p = i;
continue;
}
while(top && h[sta[top]] > h[i]) top --;
r[i] = sta[top] - i - (sta[top] > p),sta[++top] = i;
}
// for(int i = 2; i <= len; i ++) cout << l[i] << ' ' << r[i] << endl;
for(int i = 2; i <= len; i ++) if(s[sa[i] - 1] != 'z' + 1) sum += 1ll * l[i] * r[i] * h[i];
// cout << sum << endl;
return sum;
}
int main(){
cin >> s1 >> s2;
cout << sum(s1 + char('z' + 1) + s2) - sum(s1) - sum(s2) << endl;
return 0;
}
[AHOI2013]差异:后缀数组,LCP,单调栈
跟上题一样差不多,调了几个小时发现初始化时少加了一
#include <iostream>
using namespace std;
const int maxn = 5e5 + 50;
int n,cnt,top,t[maxn],x1[maxn],x2[maxn],bk[maxn],sa[maxn],rk[maxn],h[maxn],l[maxn],r[maxn],sta[maxn];
long long ans;
string s;
void get_SA(){
int mx = 0;
for(int i = 1; i <= n; i ++) x1[i] = s[i - 1],bk[x1[i]] ++,mx = max(mx,x1[i]);
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = n; i >= 1; i --) sa[bk[x1[i]] --] = i;
for(int k = 1; k <= n; k <<= 1){
cnt = 0;
for(int i = n - k + 1; i <= n; i ++) x2[++cnt] = i;
for(int i = 1; i <= n; i ++) if(sa[i] > k) x2[++cnt] = sa[i] - k;
for(int i = 1; i <= mx; i ++) bk[i] = 0;
for(int i = 1; i <= n; i ++) bk[x1[i]] ++;
for(int i = 1; i <= mx; i ++) bk[i] += bk[i - 1];
for(int i = n; i >= 1; i --) sa[bk[x1[x2[i]]] --] = x2[i];
for(int i = 1; i <= n; i ++) t[i] = x1[i];
cnt = 0;
for(int i = 1; i <= n; i ++){
if(t[sa[i]] != t[sa[i - 1]] || t[sa[i] + k] != t[sa[i - 1] + k]) cnt ++;
x1[sa[i]] = cnt;
}
if(cnt == n) break;
else mx = cnt;
}
}
void get_height(){
for(int i = 1; i <= n; i ++) rk[sa[i]] = i;
int p = 0;
for(int i = 1; i <= n; i ++){
if(rk[i] == 1) continue;
if(p) p --;
int t = sa[rk[i] - 1];
while(i + p <= n && t + p <= n && s[i + p - 1] == s[t + p - 1]) p ++;
h[rk[i]] = p;
}
}
int main(){
cin >> s;
n = s.size();
get_SA();
get_height();
top = 0,sta[0] = 1;
for(int i = 2; i <= n; i ++){
while(top && h[sta[top]] >= h[i]) top --;
l[i] = i - sta[top],sta[++top] = i;
}
top = 0,sta[0] = n + 1;
for(int i = n; i >= 2; i --){
while(top && h[sta[top]] > h[i]) top --;
r[i] = sta[top] - i,sta[++top] = i;
}
ans = 1ll * n * (n - 1) * (n + 1) / 2;
for(int i = 2; i <= n; i ++) ans -= 2ll * l[i] * r[i] * h[i];
cout << ans << endl;
return 0;
}
点分树模板
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e5 + 50,maxm = 100 * maxn,inf = 1e9;
int n,m,type,x,y,rt,cnt,a[maxn],last[maxn],d[maxn],fst[maxn],Log[2 * maxn],f[2 * maxn][20],vis[maxn],size[maxn],maxs[maxn],dsiz[maxn],dfa[maxn];
struct edge{
int v,nxt;
}e[2 * maxn];
struct Segment_Tree{
int cnt,rt[maxn],val[maxm],ls[maxm],rs[maxm];
void modify(int p,int k,int &x,int l,int r){
if(!x) x = ++cnt;
val[x] += k;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) modify(p,k,ls[x],l,mid);
else modify(p,k,rs[x],mid + 1,r);
}
int sum(int L,int R,int x,int l,int r){
if(!x) return 0;
if(L <= l && R >= r) return val[x];
int mid = (l + r) >> 1,s = 0;
if(L <= mid) s += sum(L,R,ls[x],l,mid);
if(R > mid) s += sum(L,R,rs[x],mid + 1,r);
return s;
}
}T1,T2;
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
void insert(int x,int y){
cnt ++,e[cnt].v = y,e[cnt].nxt = last[x],last[x] = cnt;
}
int lower(int u,int v){
if(d[u] < d[v]) return u;
else return v;
}
void dfs(int u,int fa){
d[u] = d[fa] + 1;
if(u == 1) d[u] = 0;
cnt ++,f[cnt][0] = u,fst[u] = cnt;
for(int i = last[u]; i; i = e[i].nxt){
int v = e[i].v;
if(v == fa) continue;
dfs(v,u);
f[++cnt][0] = u;
}
}
void ST_pre(){
for(int i = 2; i <= cnt; i ++) Log[i] = Log[i >> 1] + 1;
for(int i = cnt; i >= 1; i --)
for(int j = 1; i + (1 << j) - 1 <= cnt; j ++)
f[i][j] = lower(f[i][j - 1],f[i + (1 << (j - 1))][j - 1]);
}
int Lca(int u,int v){
if(fst[u] > fst[v]) swap(u,v);
int t = Log[fst[v] - fst[u] + 1];
return lower(f[fst[u]][t],f[fst[v] - (1 << t) + 1][t]);
}
int dis(int u,int v){
return d[u] + d[v] - 2 * d[Lca(u,v)];
}
void getrt(int u,int fa,int totsiz){
size[u] = 1,maxs[u] = 0;
for(int i = last[u]; i; i = e[i].nxt){
int v = e[i].v;
if(vis[v] || v == fa) continue;
getrt(v,u,totsiz);
size[u] += size[v],maxs[u] = max(maxs[u],size[v]);
}
maxs[u] = max(maxs[u],totsiz - size[u]);
if(maxs[u] < maxs[rt]) rt = u;
}
void divide(int u,int totsiz){
vis[u] = 1,dsiz[u] = totsiz;
for(int i = last[u]; i; i = e[i].nxt){
int v = e[i].v,vsiz;
if(vis[v]) continue;
if(size[v] < size[u]) vsiz = size[v];
else vsiz = totsiz - size[u];
rt = 0;
getrt(v,u,vsiz);
dfa[rt] = u;
divide(rt,vsiz);
}
}
void update(int u,int k){
int now = u;
while(now){
int fa = dfa[now];
T1.modify(dis(u,now),k,T1.rt[now],0,dsiz[now]);
if(fa) T2.modify(dis(u,fa),k,T2.rt[now],0,dsiz[now] + 1);
now = fa;
}
}
int query(int u,int k){
int now = u,last = 0,s = 0;
while(now){
int d = dis(u,now);
if(d > k){
last = now,now = dfa[now];
continue;
}
s += T1.sum(0,k - d,T1.rt[now],0,dsiz[now]);
if(last) s -= T2.sum(0,k - d,T2.rt[last],0,dsiz[last] + 1);
last = now,now = dfa[now];
}
return s;
}
int main(){
n = read(),m = read();
for(int i = 1; i <= n; i ++) a[i] = read();
for(int i = 1; i < n; i ++){
x = read(),y = read();
insert(x,y),insert(y,x);
}
cnt = 0;
dfs(1,0);
ST_pre();
rt = 0,maxs[0] = inf;
getrt(1,0,n);
divide(rt,n);
for(int i = 1; i <= n; i ++) update(i,a[i]);
int last = 0;
for(int i = 1; i <= m; i ++){
type = read(),x = read() ^ last,y = read() ^ last;
if(type == 0) printf("%d\n",last = query(x,y));
else update(x,y - a[x]),a[x] = y;
}
return 0;
}
[NOI2015]寿司晚宴: 玄妙状压DP
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 550,maxm = 260,p[8] = {2,3,5,7,11,13,17,19};
int n;
long long ans,mod,f[maxm][maxm],f1[maxm][maxm],f2[maxm][maxm];
struct node{
int s,big;
}a[maxn];
bool cmp(node x,node y){
return x.big < y.big;
}
int main(){
cin >> n >> mod;
for(int i = 1; i < n; i ++){
int t = i + 1;
for(int j = 0; j < 8; j ++){
if(t % p[j] == 0){
while(t % p[j] == 0) t /= p[j];
a[i].s |= 1 << j;
}
}
a[i].big = t;
// cout << i + 1 << ' ' << a[i].big << endl;
}
sort(a + 1,a + n,cmp);
f[0][0] = 1;
for(int i = 1; i < n; i ++){
if(a[i].big != a[i - 1].big || a[i].big == 1){
for(int j = 0; j <= 255; j ++)
for(int k = 0; k <= 255; k ++)
f1[j][k] = f2[j][k] = f[j][k];
}
for(int j = 255; j >= 0; j --){
for(int k = 255; k >= 0; k --){
if(!((j | a[i].s) & k)) f1[j | a[i].s][k] = (f1[j | a[i].s][k] + f1[j][k]) % mod;
if(!(j & (k | a[i].s))) f2[j][k | a[i].s] = (f2[j][k | a[i].s] + f2[j][k]) % mod;
}
}
if(a[i].big != a[i + 1].big || a[i].big == 1){
for(int j = 0; j <= 255; j ++)
for(int k = 0; k <= 255; k ++)
f[j][k] = ((f1[j][k] + f2[j][k] - f[j][k]) % mod + mod) % mod;
}
}
// for(int i = 0; i <= 4; i ++)
// for(int j = 0; j <= 4; j ++)
// cout << i << ' ' << j<< ' ' << f[i][j] << endl;
for(int i = 0; i <= 255; i ++)
for(int j = 0; j <= 255; j ++)
ans = (ans + f[i][j]) % mod;
cout << ans << endl;
return 0;
}