HL 7.18 杂题整理 随笔

弹飞绵羊:

源神推荐的LCT模板题,于是就去学习了一下,学的是Chdy的板子,不好看怪他;

这个题目,将当前点和他即将弹到的点link起来,如果被弹飞了,那么这条边就不存在。

查询弹飞的步数,就是查询该点到其所属原树中根节点的路径的size

其实当时还在疑惑为什么Chdy的题解里没有makeroot的操作;

根据此题,我们并不需要查询或者更改指定路径x-y的信息。

也就是说,我们根本不需要换根!

原来需要换根的split,link,cut操作,我们可以根据题目适当调整一下;

查询原本需要split,我们直接access(x),splay(x)输出xsize

连边原本需要link,题目保证了是一棵树,我们直接改x的父亲。

断边原本需要cut,然而我们确定其父亲的位置,access(x),splay(x)后,x的父亲一定在xx的左子树中(LCT的性质),直接双向断开连接。

自然少了一些函数(pushdown,makeroot,findroot,split,link,cut

那么这个题就做完了;也就是因为我这个题好多函数没有打好多函数,导致后面有道LCT有点头大;

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
template<typename T>inline void read(T &x)
{
    x=0;
    register int f=1;
    register char ch=getchar();
    while (!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

int n,m,c[N][2],f[N],s[N],a[N];

inline int get(int x) {
    return c[f[x]][0]==x||c[f[x]][1]==x;
}

inline void pushup(int x) {
    s[x]=s[c[x][0]]+s[c[x][1]]+1;
}

inline void rotate(int x) {
    int old=f[x],oldf=f[old],k=c[old][1]==x;
    if(get(old))    c[oldf][c[oldf][1]==old]=x;
    c[old][k]=c[x][k^1];c[x][k^1]=old;
    if(c[old][k])    f[c[old][k]]=old;
    f[old]=x; f[x]=oldf;pushup(old);
}

inline void splay(int x) {
    while(get(x)) {
        int old=f[x],oldf=f[old];
        if(get(old)) rotate((c[old][0]==x)^(c[oldf][0]==old)?x:old);
        rotate(x);
    }
    pushup(x);
}
inline void access(int x) {
    for(int y=0;x;x=f[y=x])
        splay(x), c[x][1]=y, pushup(x);
}

inline void cut(int x,int y) {
    access(x);splay(x);
    if(y) splay(y),c[y][1]=0,f[x]=0;
    pushup(x);
}

int main() {
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    read(n);
    for(int i=1;i<=n;++i) {
        s[i]=1; read(a[i]);
        if(i+a[i]<=n) f[i]=i+a[i];
    }
    read(m);
    for(int i=1,p,x,y;i<=m;i++) {
        read(p); read(x);
        x+=1;
        if(p==1) {
            access(x); splay(x);
            printf("%d\n",s[x]);
        }
        else {
            read(y);
            int last=a[x];a[x]=y;
            cut(x,x+last>n?0:x+last);
            if(x+a[x]<=n) f[x]=x+a[x];
        }
    }
    return 0;
}
View Code

部落冲突

无脑LCT,其实是不会树链剖分+线段树;

开战cut,停战link,判断联通findroot,另外那些函数写的时候注意一点就好了;

makeroot(x) 把x变为原树的根,即为换根,findroot(x)寻找x在原树的根,split(x,y)提取出来x,y的路径,splay(x)把x弄到当前splay的根,get(x)判断x是不是当前的根;

#include<bits/stdc++.h>
using namespace std;
const int N=300010;
template<typename T>inline void read(T &x) {
    x=0;
    register int f=1;
    register char ch=getchar();
    while (!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int top; 
int c[N][2],f[N],s[N],r[N];

void pushdown(int x) {
    if(r[x]) {
        r[x]=0;
        int t=c[x][0];
        r[c[x][0]=c[x][1]]^=1;
        r[c[x][1]=t]^=1;
    }
}

inline int get(int x) {
    return c[f[x]][0]==x||c[f[x]][1]==x;
}

inline void rotate(int x) {
    int old=f[x],oldf=f[old],k=c[old][1]==x;
    if(get(old))    c[oldf][c[oldf][1]==old]=x;
    c[old][k]=c[x][k^1]; c[x][k^1]=old;
    if(c[old][k])    f[c[old][k]]=old;
    f[old]=x; f[x]=oldf;
}

inline void splay(int x) {
    int y=x;top=0;
    s[++top]=y;
    while(get(y))s[++top]=y=f[y];
    while(top)pushdown(s[top--]);
    while(get(x)) {
        int old=f[x],oldf=f[old];
        if(get(old)) rotate((c[old][0]==x)^(c[oldf][0]==old)?x:old);
        rotate(x);
    }
}

inline void access(int x) {
    for(int y=0;x;x=f[y=x])
        splay(x),c[x][1]=y;
}

inline int findroot(int x) {
    access(x); splay(x);
    while(c[x][0])    pushdown(x),x=c[x][0];
    splay(x);
    return x;
}

void makeroot(int x) {
    access(x);splay(x);
    r[x]^=1;pushdown(x);
}

inline void link(int x,int y) {
    makeroot(x);
    f[x]=y;
}

inline void cut(int x,int y) {
    makeroot(x);
    access(y);
    splay(y);
    c[y][0]=0,f[x]=0;
}

int n,m,id,x[N],y[N];
char ch[3];

int main() {
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    read(n); read(m);
    int a,b,u,v,p=0;
    for(int i=1;i<n;i++) {
        read(a); read(b);
        link(a,b);
    }
    for(int i=1;i<=m;i++) {
        scanf("%s",ch);
        if(ch[0]=='Q') {
            read(u); read(v);
            if(findroot(u)==findroot(v)) {
                printf("Yes\n");
            }
            else printf("No\n");
        }
        else if(ch[0]=='U') {
            read(id);
            link(x[id],y[id]);
        }
        else {
            read(u); read(v);
            x[++p]=u;y[p]=v;
            cut(u,v);
        }
    }
    return 0;
}
View Code

文本生成器

AC自动机+dp;

首先我们知道对于正向求解问题是比较困难的,那么我们可以反向思维,求其补集,然后总方案数相减;

这种思维是比较常用的;

dp[i][j]表示当前构建字符长度为i,对应trie树上的j节点,从父亲向儿子转移就好了;

//快速幂记得取模;

#include<bits/stdc++.h>
using namespace std;
const int N=6010;
const int mod=10007;
template<typename T>inline void read(T &x) {
    x=0;
    register int f=1;
    register char ch=getchar();
    while (!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

int trie[N][26],idx,n,m,cnt[N],fail[N],f[200][N];
char s[N]; 

inline int power(int a,int b) {
    int ans=1;
    while(b) {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

inline void insert(char *s) {
    int p=0;
    for(int i=0;s[i];i++) {
        int ch=s[i]-'A';
        if(!trie[p][ch]) trie[p][ch]=++idx;
        p=trie[p][ch];
    } 
    cnt[p]|=1;
}

inline void build() {
    queue<int> q;
    memset(fail,0,sizeof(fail));
    for(int i=0;i<26;i++) if(trie[0][i]) q.push(trie[0][i]);
    while(q.size()) {
        int k=q.front();q.pop();
        for(int i=0;i<26;i++) {
            if(trie[k][i]) {
                q.push(trie[k][i]);
                fail[trie[k][i]]=trie[fail[k]][i];
                cnt[trie[k][i]]|=cnt[trie[fail[k]][i]];
            }
            else trie[k][i]=trie[fail[k]][i];
        }
    }
}

int main() {
    read(n); read(m);
    for(int i=1;i<=n;i++) {
        scanf("%s",s);
        insert(s);
    }
    build();
    f[0][0]=1;
    for(int T=1;T<=m;T++) {
        for(int i=0;i<=idx;i++) {
            for(int j=0;j<26;j++) {
                if(!cnt[trie[i][j]])
                (f[T][trie[i][j]]+=f[T-1][i])%=mod;
            }
        }
    }
    int ans=0;
    for(int i=0;i<=idx;i++)
            ans=(ans+f[m][i])%mod;
    printf("%d\n",((power(26,m)-ans)%mod+mod)%mod);
}
View Code

单词:

AC自动机的题;

不要问我为什么天天写AC自动机,因为天天赌题,赌AC自动机的题,温馨提示:久赌必输;

这个就是建出fail数,然后求出子数大小,就是答案;

fail树的父亲节点是其儿子节点的前缀;

#include<bits/stdc++.h>
using namespace std;
const int N=1000100;
template<typename T>inline void read(T &x) {
    x=0;
    register int f=1;
    register char ch=getchar();
    while (!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int tot,n,idx,fail[N],trie[N][26],lin[N],orz[N];
char s[N];
long long size[N];
struct gg {
    int y,next;
}a[N<<1];

inline void add(int x,int y) {
    a[++tot].y=y; a[tot].next=lin[x]; lin[x]=tot;
}

inline void insert(char *s,int v) {
    int p=0;
    for(int i=0;s[i];i++) {
        int ch=s[i]-'a';
        if(!trie[p][ch]) trie[p][ch]=++idx;
        p=trie[p][ch]; size[p]++;
    }
    orz[v]=p;
}


inline void build() {
    queue<int> q;
    memset(fail,0,sizeof(fail));
    for(int i=0;i<26;i++) if(trie[0][i]) q.push(trie[0][i]);
    while(q.size()) {
        int k=q.front(); q.pop();
        for(int i=0;i<26;i++) {
            if(trie[k][i]) {
                fail[trie[k][i]]=trie[fail[k]][i];
                q.push(trie[k][i]);
            }
            else trie[k][i]=trie[fail[k]][i];
        }
    }
}

inline void dfs(int x) {
    for(int i=lin[x];i;i=a[i].next) {
        int y=a[i].y;
        dfs(y);
        size[x]+=size[y];
    }
}

int main() {
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++) {
        scanf("%s",s);
        insert(s,i);
    }
    build();
    for(int i=1;i<=idx;i++) {
        add(fail[i],i);
    }
    dfs(0);
    for(int i=1;i<=n;i++) {
        printf("%lld\n",size[orz[i]]);
    }
    return 0;
}
View Code

 

posted @ 2019-07-18 08:16  Tyouchie  阅读(189)  评论(0编辑  收藏  举报