4.7-4.12做题情况

这周看了半天后缀自动机没看懂,看了半天多项式又没看懂,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 C10,容易想到对每种颜色分别建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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值