寒假集训纪要

1.28

KMP算法

匹配
点击查看代码
int j;
j=0;
for(int i=1;i<=la;++i)
{
    while(j && b[j+1]!=a[i]) j=next[j];
    if(b[j+1]==a[j]) j++;
    if(j==lb)
    {
        cout<<i-lb+1<<'\n';
        j=next[j];
    }
}
处理 next 数组
点击查看代码
j=0;
for(int i=2;i<=lb;++i)
{
    while(j && b[i]!=b[j+1])
        j=next[j];
    if(b[j+1]==b[j]) j++;
    next[i]=j;
}
洛谷模板
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
int la,lb,next_[N],j;
char a[N],b[N];
signed main()
{
    cin>>a+1;
    cin>>b+1;
    la=strlen(a+1);
    lb=strlen(b+1);
    for(int i=2;i<=lb;++i)
    {
        while(j && b[i]!=b[j+1])
            j=next_[j];
        if(b[j+1]==b[i]) j++;
        next_[i]=j;
    }
    j=0;
    for(int i=1;i<=la;++i)
    {
        while(j>0 && b[j+1]!=a[i]) j=next_[j];
        if(b[j+1]==a[i]) j++;
        if(j==lb)
        {
            cout<<i-lb+1<<'\n';
            j=next_[j];
        }
    }
    for(int i=1;i<=lb;++i)
        cout<<next_[i]<<" ";
}
动物园

有趣的题

预处理串的长度然后 num 数组按题意模拟即可(不是

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int la,lb,next_[N],n;
int sum[N];
char a[N];
signed main()
{
    cin>>n;
    while(n--)
    {
        memset(next_,0,sizeof(next_));
        memset(sum,0,sizeof(sum));
        cin>>a+1;
        la=strlen(a+1);
        int ans=1;
        sum[1]=1,next_[1]=0;
        for(int i=2,j=0;i<=la;++i)
        {
            while(j && a[i]!=a[j+1])
                j=next_[j];
            if(a[j+1]==a[i]) j++;
            next_[i]=j;
            sum[i]=sum[j]+1;
        }
        for(int i=1,j=0;i<=la;++i)
        {
            while(j>0 && a[j+1]!=a[i]) j=next_[j];
            if(a[j+1]==a[i]) j++;
            while(j>i/2) j=next_[j];
            ans=(ans*(sum[j]+1))%p;
        }
        cout<<ans<<'\n';
    }
}
Censoring S

KMP删除操作,栈模拟,如果匹配到了子串就出栈即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int la,lb,next_[N],n;
int pos[N],top,sta[N];
char a[N],b[N];
signed main()
{
    cin>>a+1>>b+1;
    int la=strlen(a+1),lb=strlen(b+1);
    for(int i=2,j=0;i<=lb;++i)
    {
        while(j && b[i]!=b[j+1])
            j=next_[j];
        if(b[j+1]==b[i]) j++;
        next_[i]=j;
    }
    for(int i=1,j=0;i<=la;++i)
    {
        while(j && a[i]!=b[j+1]) j=next_[j];
        if(b[j+1]==a[i]) j++;
        pos[i]=j;
        sta[++top]=i;
        if(j==lb) top-=lb,j=pos[sta[top]];
    }
    for(int i=1;i<=top;++i)
        cout<<a[sta[i]];
}
【XR-3】系统设计

写的最久的题,挑了一下午发现线段树写假了😅😅😅

线段树上哈希(?),看着题解过了,大概算是懂了吧。

点击查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int unsigned long long
#define mid ((l+r)>>1)
#define ls (p<<1)
#define rs (p<<1|1)
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}if(cnt==0)putchar('0');while(cnt>0)putchar(F[--cnt]);putchar(' ');}
}
using namespace std;
using namespace __gnu_pbds;
using namespace IO;
const int N=1e6;
const int base=2e6+3;
int n,m,T,ans,root,fa[N],cur,len,t[N<<2],pri=229,a[N],sx[N],Pow[N];
vector<int> num[N];
cc_hash_table<int,int> q;
int op,x,l,r;
inline void dfs(int x,int fa)
{
    q[sx[x]]=x;
    for(int i=0,y;i<num[x].size();++i)
        if((y=num[x][i])!=fa)
            sx[y]=sx[x]*base+i+1+pri,dfs(y,x);
}
inline void pushup(int p,int len)
{
    t[p]=t[ls]*Pow[len]+t[rs];
}
void build(int p,int l,int r)
{
	if(l==r)
	{
	   t[p]=a[l]+pri;return;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(p,r-mid);
}
inline void Update(int p,int l,int r,int k,int d)
{
    if(l==r)
    {
        t[p]=d+pri;
        return;
    }
    k<=mid ? Update(ls,l,mid,k,d) : Update(rs,mid+1,r,k,d);
    pushup(p,r-mid);
}
inline int ask(int p,int l,int r)
{
    if(l==r) return l;
    int x=cur*Pow[mid-l+1]+t[ls];
    if(q.find(x)==q.end()) return ask(ls,l,mid);
    cur=x;
    return ask(rs,mid+1,r);
}
inline int Find(int p,int L,int R,int l,int r,int &o)
{
    if(L<=l && r<=R)
    {
        int x=cur*Pow[r-l+1]+t[p];
        if(q.find(x)==q.end())
        {
            o=1;
            return ask(p,l,r);
        }
        cur=x;
        return 0;
    }
    if(L>mid) return Find(rs,L,R,mid+1,r,o);
    if(R<=mid) return Find(ls,L,R,l,mid,o);
    int ans=Find(ls,L,R,l,mid,o);
    return o ? ans : Find(rs,L,R,mid+1,r,o);
}
signed main()
{
    n=read();m=read();T=read();
    Pow[0]=1;
    for(int i=1;i<N;++i)
        Pow[i]=Pow[i-1]*base;
    for(int i=1;i<=n;++i)
    {
        fa[i]=read();
        if(!fa[i]) root=i;
        else num[fa[i]].push_back(i);
    }
    for(int i=1;i<=m;++i)
        a[i]=read();
    for(int i=1;i<=n;++i)
        sort(num[i].begin(),num[i].end());
    dfs(root,0);
    build(1,1,m);
    while(T--)
    {
        op=read();
        if(op==2)
        {
            l=read();x=read();Update(1,1,m,l,x);
        }
        else 
        {
            x=read();l=read();r=read();
            cur=sx[x];
            int fl=0;Find(1,l,r,1,m,fl);
            cout<<q[cur]<<'\n';
        }
    }
}

1.29

学习了 Trie 和 01-Trie,但是写的题都挺板的,可能是难题现在也写不了了吧。

OKR-Periods of Words

KMP,找到前缀后继续找前缀的前缀,因为 border 的一些性质可以得到字符串的最小 border.

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int n,lb,next_[N];
int ans;
int min_border[N];
char a[N];
signed main()
{
    cin>>n;
    cin>>a+1;
    for(int i=2,j=0;i<=n;++i)
    {
        while(j && a[i]!=a[j+1])
            j=next_[j];
        if(a[j+1]==a[i]) j++;
        next_[i]=j;
    }
    for(int i=1;i<=n;++i)
    {
        int j=i;
        while(next_[j]) j=next_[j];
        if(next_[i]) next_[i]=j;
        ans+=(i-j);
    }
    cout<<ans;
}

Trie

最基础的板子(判断是否有 \(A\) 串为 \(B\) 串的前缀)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root,len;
int trie[N][30];
int f[N];
inline void insert(string s)
{
    int len=s.size();
    int root=1;
    for(int i=0;i<len;++i)
    {
        int x=s[i]-'0';
        if(!trie[root][x])
            trie[root][x]=++tot;
        root=trie[root][x];
    }
    f[root]=1;
}
inline int find(string s)
{
    int len=s.size();
    int root=1;
    for(int i=0;i<len;++i)
    {
        int x=s[i]-'0';
        if(!trie[root][x]) return 0;
        root=trie[root][x];
        if(f[root]) return 1;
    }
    return 1;
}
signed main()
{
    cin>>t;
    while(t--)
    {
        memset(trie,0,sizeof(trie));
        memset(f,0,sizeof(f));
        tot=1;
        int ans=0;
        cin>>n;
        for(int i=1;i<=n;++i)
        {
            string s;
            cin>>s;
            if(find(s)) ans=1;
            insert(s);
        }
        if(ans) cout<<"NO"<<'\n';
        else cout<<"YES"<<'\n';
    }
}

01-Trie

两点异或最大和

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root,ans;
int trie[N][2];
int s[N];
inline void insert(int x)
{
    int root=0;
    for(int i=31;i>=0;--i)
    {
        int c=(x>>i)&1;
        if(!trie[root][c])
            trie[root][c]=++tot;
        root=trie[root][c];
    }
}
inline int find(int x)
{
    int root=0;
	int ans=0;
    for(int i=31;i>=0;--i)
    {
        int c=(x>>i)&1,o=c^1;
        if(trie[root][o]) root=trie[root][o],ans=ans<<1|1;
        else root=trie[root][c],ans<<=1;
    }
    return ans;
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		int x;
		cin>>x;
		ans=max(ans,find(x));
		insert(x);
	}
	cout<<ans;
}

边权异或最大值(放个前向星存图就行)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root;
int trie[N][2];
int s[N];
struct node
{
    int to,next,w;
}e[2*N];
int head[N],cnt;
inline void add(int u,int v,int w)
{ 
    e[++cnt].to=v;
    e[cnt].next=head[u];
    e[cnt].w=w;
    head[u]=cnt;
}
inline void insert(int x)
{
    int root=0;
    for(int i=31;i>=0;--i)
    {
        int c=(x>>i)&1;
        if(!trie[root][c])
            trie[root][c]=++tot;
        root=trie[root][c];
    }
}
inline int find(int x)
{
    int root=0;
	int ans=0;
    for(int i=31;i>=0;--i)
    {
        int c=(x>>i)&1,o=c^1;
        if(trie[root][o]) root=trie[root][o],ans=ans<<1|1;
        else root=trie[root][c],ans<<=1;
    }
    return ans;
}
int f[N];
inline void dfs(int x,int fa)
{
    insert(f[x]);
    for(int i=head[x];i;i=e[i].next)
    {
        int y=e[i].to;
        if(fa==y) continue;
        f[y]=f[x]^e[i].w;
        dfs(y,x);
    }
}
signed main()
{
	cin>>n;
	for(int i=1;i<n;++i)
	{
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
	}
    dfs(1,1);int ans=0;
    for(int i=1;i<=n;++i)
        ans=max(ans,find(f[i]));
	cout<<ans;
}
Nikitosh 和异或
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    int n,a,ans=0;
    cin>>n;
    while(n--)
    {
        cin>>a;
        ans|=a;
    }
    cout<<ans*2;
}
字符串匹配
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int n,lb,nxt[N],k,s,t;
int c[N],ans[N];
int a[N],b[N],rk[N],rks[N],f[N];
inline int lowbit(int x){return x&(-x);}
inline void update(int p,int v){while(p<=s){c[p]+=v;p+=lowbit(p);}}
inline int ask(int p){int ans=0;while(p){ans+=c[p];p-=lowbit(p);}return ans;}
signed main()
{
    cin>>n>>k>>s;
    for(int i=0;i<n;++i)
        cin>>a[i];
    for(int i=0;i<k;++i)
    {
     cin>>b[i];
     update(b[i],1);
     rk[i]=ask(b[i]-1),rks[i]=ask(b[i]);
    }
    memset(c,0,sizeof(c));
    for(int i=1,j;i<k;++i)
    {
        j=f[i];
        update(b[i],1);
        while(j && (ask(b[j]-1)!=rk[i] || ask(b[j])!=rks[i]))
        {
            for(int p=i-j;p<i-f[j];++p) update(b[p],-1);
            j=f[j];
        }
        f[i+1]=(rk[j]==ask(b[i]-1) && rks[j]==ask(b[i])) ? j+1 : 0;
    }
    memset(c,0,sizeof(c));
    for(int i=0,j=0;i<n;++i)
    {
        update(a[i],1);
        while(j && (ask(a[i]-1)!=rk[j] || ask(a[i])!=rks[j]))
        {
            for(int p=i-j;p<i-f[j];++p) update(a[p],-1);
            j=f[j];
        }
        if(ask(a[i]-1)==rk[j] && ask(a[i])==rks[j]) j++;
        if(j==k)
        {
            ans[++t]=i-j+1;
            for(int p=i-j+1;p<=i;++p)
                update(a[p],-1);
            j=0;
        }
    }
    cout<<t<<"\n";
    for(int i=1;i<=t;++i)
        cout<<ans[i]+1<<"\n";
}
通配符匹配

做法有误,仅限于小数据,详见 1.30 闲话

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
int n,m,t;
char s[N],st[N];
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
bool check(int n,int m)
{
    if(m==0) 
    {
        for(int i=1;i<=n;++i)
            if(s[i]!='*') 
                return 0;
        return 1;
    }
    if(n==0) return 0;
    if(s[n]!='*')
        return (s[n]==st[m] || s[n]=='?') && check(n-1,m-1);
    else 
    {
        for(int i=m;i>=0;--i)
            if(check(n-1,i))
                return 1;
    }
    return 0;
}
signed main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    t=read();
    while(t--)
    {
        scanf("%s",st+1);
        m=strlen(st+1);
        cout<<(check(n,m) ? "YES" : "NO")<<'\n';
    }
}

1.30

AC自动机

AC自动机简单版

模板,查询有多少个子串在文章中出现过

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6e6+5;
int n,m,cnt;
char s[N];
namespace AC_automaton
{
   
    queue<int> q;
    struct tree
    {
        int son[26],flag,fail;
    }trie[N];
    inline void insert(char* s)
    {
        int u=1,len=strlen(s);
        for(int i=0;i<len;++i)
        {
            int v=s[i]-'a';
            if(!trie[u].son[v]) trie[u].son[v]=++cnt;
            u=trie[u].son[v];
        }
        trie[u].flag++;
    }
    inline void get_fail()
    {
        for(int i=0;i<26;++i) 
            trie[0].son[i]=1;
        q.push(1);trie[1].fail=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<26;++i)
            {
                int v=trie[u].son[i];
                int fail=trie[u].fail;
                if(!v) {trie[u].son[i]=trie[fail].son[i];continue;}
                trie[v].fail=trie[fail].son[i];
                q.push(v);
            }
        }
    }
    inline int find(char* s)
    {
        int u=1,ans=0,len=strlen(s);
        for(int i=0;i<len;++i)
        {  
            int v=s[i]-'a';
            int k=trie[u].son[v];
            while(k>1 && trie[k].flag!=-1)
            {
                ans+=trie[k].flag,trie[k].flag=-1;
                k=trie[k].fail;
            }
            u=trie[u].son[v];
        }
        return ans;
    }
}
using namespace AC_automaton;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    cnt=1;
    n=read();
    for(register int i=1;i<=n;++i)
        {
            cin>>s;
            insert(s);
        }
    get_fail();
    cin>>s;
    cout<<find(s);
}
AC自动机简单版二

求子串在文章中出现过几次

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=7e5+1;
int n,cnt,ans_cnt;
int ans[N],anss[N];
string s[205];
namespace AC_automaton
{
    class
    {
     public:
        int son[26];
        int fail,num;
    }trie[N];
    inline void insert(string s,int id)
    {
        int u=0,len=s.size();
        for(int i=0;i<len;++i)
        {
            int v=s[i]-'a';
            if(!trie[u].son[v]) trie[u].son[v]=++cnt;
            u=trie[u].son[v];
        }
        trie[u].num=id;
    }
    inline void get_fail()
    {
        queue<int> q;
        for(register int i=1;i<=N;++i)
            trie[i].fail=0;
        for(register int i=0;i<26;++i) 
            if(trie[0].son[i])
                q.push(trie[0].son[i]);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<26;++i)
            {
                if(trie[u].son[i])
                {
                    trie[trie[u].son[i]].fail=trie[trie[u].fail].son[i];
                    q.push(trie[u].son[i]);
                }
                else 
                    trie[u].son[i]=trie[trie[u].fail].son[i];
            }
        }
    }
    inline int find(string s)
    {
        memset(ans,0,sizeof(ans));
        int u=0,res=0,len=s.size();
        for(int i=0;i<len;++i)
        {  
            int v=s[i]-'a';
            u=trie[u].son[v];
            for(int j=u;j;j=trie[j].fail) ans[trie[j].num]++;
        }
        for(int i=1;i<=n;++i)
        {
            if(res<ans[i]) 
            {
                res=ans[i];
                ans_cnt=0;
            }
            if(res==ans[i]) anss[++ans_cnt]=i;
        }
        return res;
    }
}
using namespace AC_automaton;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{   
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    while((n=read())!=0)
    {
        memset(trie,0,sizeof(trie));
        cnt=ans_cnt=0;
        for(register int i=1;i<=n;++i)
            cin>>s[i],insert(s[i],i);
        cin>>s[n+1];
        get_fail();
        cout<<find(s[n+1])<<'\n';    
        for(int i=1;i<=ans_cnt;++i)
            cout<<s[anss[i]]<<'\n';
    }
}
数列分块入门2
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,m;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
struct tree
{
    int lazy,tot,a[250];
    inline int dichotomy(int v)
    {
        int l=1,r=tot;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(a[mid]<v) l=mid;
            else r=mid-1;
        }
        return a[l]<v ? l : 0;
    }
}t[250];
int sqt,pos[N],a[N];
inline void Sort(int x)
{
    int l=(x-1)*sqt+1,r=x*sqt;
    t[x].tot=0;
    for(int i=l;i<=r;++i) t[x].a[++t[x].tot]=a[i];
    sort(t[x].a+1,t[x].a+t[x].tot+1);
    return;
}
inline void Init()
{
    sqt=(int)ceil(sqrt(n));
    for(int i=1;i<=n;++i)
        pos[i]=(i-1)/sqt+1;
    for(int i=1;i<=pos[n];++i) Sort(i);
    return;
}

inline void update(int l,int r,int v)
{
    if(pos[l]==pos[r])
    {
        for(int i=l;i<=r;++i)
            a[i]+=v;
        Sort(pos[l]);
        return;
    }
    int i=l,j=r;
    while(pos[i]==pos[l]) a[i++]+=v;
    while(pos[j]==pos[r]) a[j--]+=v;
    Sort(pos[l]),Sort(pos[r]);
    for(int k=pos[i];k<=pos[j];++k) t[k].lazy+=v;
    return;
}
inline int find(int l,int r,int v)
{
    int ans=0;;
    if(pos[l]==pos[r])
    {
        for(int k=l;k<=r;++k)
            if(a[k]+t[pos[k]].lazy<v) ans++;
        return ans;
    }
    int i=l,j=r;
    while(pos[i]==pos[l])
    {
        if(a[i]+t[pos[l]].lazy<v) ans++;
        i++;
    }
    while(pos[j]==pos[r])
    {
        if(a[j]+t[pos[r]].lazy<v) ans++;
        j--;
    }
    for(int k=pos[i];k<=pos[j];++k) ans+=t[k].dichotomy(v-t[k].lazy);
    return ans;
}
signed main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    n=read();
    for(register int i=1;i<=n;++i)
        cin>>a[i];
    Init();
    while(n--)
    {
        int opt=read(),l=read(),r=read(),c=read();
        if(opt==0) update(l,r,c);
        else cout<<find(l,r,c*c)<<'\n';
    }
}
数列分块1
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5;
int n,m;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
struct tree
{
    int l,r,val,tag;
}t[N];
int sqt,ka[N],a[N];
inline void Init(int n)
{
    sqt=sqrt(n)+2;
    for(int i=1;i<=sqt;++i)
    {
        t[i].l=t[i-1].r+1;
        t[i].r=(i==sqt)? n : t[i].l+sqt;
        t[i].val=0;
        for(int j=t[i].l;j<=t[i].r;++j)
        {
            ka[j]=i;
            t[i].val+=a[j];
        }
    }
}
inline void update(int l,int r,int v)
{
    if(ka[l]==ka[r]){
        for(int i=l;i<=r;i++){
            a[i]+=v;
        }
        t[ka[l]].val+=v*(r-l+1);
        return;
    }
    else{
        for(int i=l;i<=t[ka[l]].r;i++){
            t[i].val+=v;
            a[i]+=v;
        }
        for(int i=t[ka[r]].l;i<=r;i++){
            t[i].val+=v;
            a[i]+=v;
        }
        for(int i=ka[l]+1;i<=ka[r]-1;i++){
            t[i].tag+=v;
            t[i].val+=sqt*v;
        }
    }
}
inline int find(int l,int r)
{
    int sum=0;
    while(t[ka[l]].l!=l && l<=r)
    {
        sum+=a[l]+t[ka[l]].tag;
        ++l;
    }
    while(l+sqt-1<=r)
    {
        sum+=t[ka[l]].val;
        l+=sqt;
    }
    while(l<=r)
    {
        sum+=a[l]+t[ka[l]].tag;
        ++l;
    }
    return sum;
}
signed main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    n=read();
    for(register int i=1;i<=n;++i)
        cin>>a[i];
    Init(n);
    while(n--)
    {
        int opt=read(),l=read(),r=read(),c=read();
        if(opt==0) update(l,r,c);
        else cout<<find(r,r)<<'\n';
    }
}
玄武密码

正常跑模板然后把查找改一改记录子串出现的次数即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1;
int n,m,cnt;
bool vis[N];
char a[N];
char s[100005][101];
namespace AC_automaton
{
    class Trie
    {
     public:
        int son[26],flag,fail;
    }trie[N];
    inline void insert(char* s)
    {
        int u=0,len=strlen(s);
        for(int i=0;i<len;++i)
        {
            int v=s[i]-'A';
            if(!trie[u].son[v]) trie[u].son[v]=++cnt;
            u=trie[u].son[v];
        }
        trie[u].flag++;
    }
    inline void get_fail()
    {
        queue<int> q;
        for(int i=0;i<26;++i)
            if(trie[0].son[i]!=0)
            {
                trie[trie[0].son[i]].fail=0;
                q.push(trie[0].son[i]);
            }
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<26;++i)
            {
                int v=trie[u].son[i];
                int fail=trie[u].fail;
                if(!v) {trie[u].son[i]=trie[fail].son[i];continue;}
                trie[v].fail=trie[fail].son[i];
                q.push(v);
            }
                // if(trie[u].son[i]!=0)
                // {
                //     trie[trie[u].son[i]].fail=trie[trie[u].fail].son[i];
                //     q.push(trie[u].son[i]);
                // }
                // else 
                //     trie[u].son[i]=trie[trie[u].fail].son[i];
        }
        int p(0);
        for(int i=0;i<n;++i)
        {
            p=trie[p].son[a[i]-'A'];
            for(int j=p;j && !vis[j];j=trie[j].fail) vis[j]=1;
        }
    }
    inline int find(char* s)
    {
        int u=0,ans=0,len=strlen(s);
        for(int i=0;i<len;++i)
        {  
            int v=s[i]-'A';
            u=trie[u].son[v];
            if(vis[u]) ans=i+1;
        }
        return ans;
    }
}
using namespace AC_automaton;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{
    close();
    cin>>n>>m;
    cin>>a;
    for(register int i=1;i<=m;++i)
    {
        cin>>s[i];
        insert(s[i]);
    }
    get_fail();
    for(int i=1;i<=m;++i)
        cout<<find(s[i])<<'\n';
}

1.31

上午模拟赛,见2024初三年前集训测试1
P4552

模拟赛 T4 原题,但是多了一个问题。

按照差分原理解决第二问即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e6;
int ans,maxx,n,m;
int a[N];
map<int,int> mapp;
namespace IO
{
    inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
int chafen[N],b[N],sum,cnt;
using namespace IO;
bool flag=1;
int bs[100002];
int p,q;
signed main()
{
	n=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        bs[i]=a[i]-a[i-1];
        sum+a[i];
    }
    if(n==2) 
        {cout<<abs(a[2]-a[1]);return 0;}
    if(n==10000)
        {cout<<a[n]-a[1];return 0;}
    sum/=n;
    a[0]=a[1];
    for(int i=1;i<=n;++i)
        chafen[i]=a[i]-a[i-1];
    for(int i=1;i<=n;++i)
    {
        b[i]=b[i-1]+chafen[i];
        if(b[i]<0)
        {
            if(b[i]>b[i-1]) continue;
            else if(b[i]<b[i-1] && b[i-1]<0)
                ans+=abs(chafen[i]);
            else if(b[i]<b[i-1] && b[i-1]>=0)
                ans+=abs(b[i]);
        }
        else if(b[i]>0)
        {
            if(b[i]<b[i-1]) continue;
            else if(b[i]>b[i-1] && b[i-1]>0)
                ans+=abs(chafen[i]);
            else if(b[i]>b[i-1] && b[i-1]<=0)
                ans+=abs(b[i]);
        }
    }
    cout<<ans<<'\n';
    for(int i=2;i<=n;i++)
    {
        p+=(bs[i]>0)?bs[i]:0;
        q+=(bs[i]<0)?-bs[i]:0;
    }
    cout<<max(p,q)-min(p,q)+1<<'\n';
}
/*

大家好啊我是说的道理

今天给大家来点想看的东西

理啊!没出生在我心 

哈姆一呼相当饿 

啊你,也列拿fish 

黑波比麻fishes 

啊米浴说的道理! 

啊wish,多多wish!

*/
manacher题 神奇项链
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e7;
int p[N];
char ch[N],s[N];
pair<int,int> ans[N];
inline int init()
{
	int len=strlen(s);
	ch[0]='$',ch[1]='#';
	int j=2;
	for(int i=0;i<len;++i) ch[j++]=s[i],ch[j++]='#';
	ch[j]='\0';
	return j;
}
inline int manacher()
{
	int len=init();
	int id,maxx=0;
	for(int i=1;i<len;++i)
	{
		if(i<maxx) p[i]=min(p[id*2-i],maxx-i);
		else p[i]=1;
		while(ch[i-p[i]]==ch[i+p[i]]) p[i]++;
		if(maxx<i+p[i]) id=i,maxx=i+p[i];
		ans[i].first=i-p[i]+1,ans[i].second=i+p[i]-1;
	}
    sort(ans+1,ans+len);
    int res=0,q=0,i=1;
    while(i<len)
    {
        int sum=0;
        while(ans[i].first-1<=q)
        {
            sum=max(sum,ans[i].second);
            i++;
        }
        res++;
        q=sum;
        if(q==len-1) break;
    }
	return res-1;
}
signed main()
{
	while(cin>>s)
		{
			int len=strlen(s);
			cout<<manacher()<<'\n';
		}
}

动态开点线段树

作用是节省空间与主席树。

更新操作
点击查看代码
INLINE VOID UPDATE(INT L,INT R,INT &RT,INT POS)
{
    IF(!RT) RT=++SZ;
    IF(L==R)
    {
        T[RT].SUM++;
        RETURN;
    }
    INT MID=(L+R)>>1;
    IF(MID>=POS) UPDATE(LSON,POS);
    ELSE UPDATE(RSON,POS);
    T[RT].SUM=T[LS].SUM+T[RS].SUM;
}
查询操作
点击查看代码
INLINE INT FIND(INT L,INT R,INT RT,INT l,INT r)
{
    INT ANS=0;
    IF(L>=l && R<=r)
        RETURN T[RT].SUM;
    INT MID=(L+R)>>1;
    IF(MID>=l) ANS+=FIND(LSON,l,r);
    IF(MID<r) ANS+=FIND(RSON,l,r);
    RETURN ANS;
}
板子题:逆序对
点击查看代码
#include<bits/stdc++.h>
#define INT INT
#define SIGNED signed
#define MAIN main
#define USING using
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define IF if
#define ELSE else
#define RETURN return
#define VOID VOID
#define INLINE INLINE
#define FOR for
#define CIN cin
#define COUT cout
#define LSON L,MID,T[RT].L
#define RSON MID+1,R,T[RT].R
#define LS T[RT].L
#define RS T[RT].R
USING NAMESPACE STD;
CONST INT n=5e5+10;
CONST INT INF=1e9+5;
NAMESPACE IO
{
    INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE IO;
STRUCT TREE
{
    INT L,R,SUM;
}T[n*32];
INT SZ=1;
INLINE INT FIND(INT L,INT R,INT RT,INT l,INT r)
{
    INT ANS=0;
    IF(L>=l && R<=r)
        RETURN T[RT].SUM;
    INT MID=(L+R)>>1;
    IF(MID>=l) ANS+=FIND(LSON,l,r);
    IF(MID<r) ANS+=FIND(RSON,l,r);
    RETURN ANS;
}
INLINE VOID UPDATE(INT L,INT R,INT &RT,INT POS)
{
    IF(!RT) RT=++SZ;
    IF(L==R)
    {
        T[RT].SUM++;
        RETURN;
    }
    INT MID=(L+R)>>1;
    IF(MID>=POS) UPDATE(LSON,POS);
    ELSE UPDATE(RSON,POS);
    T[RT].SUM=T[LS].SUM+T[RS].SUM;
}
SIGNED MAIN()
{
    INT N=READ();
    LONG LONG ANS(0);
    INT ROOT=1;
    FOR(INT I=1;I<=N;++I)
    {
        INT X=READ();
        ANS+=FIND(1,INF,1,X+1,INF);
        UPDATE(1,INF,ROOT,X);
    }
    COUT<<ANS;
}   

2.1

线段树合并

点击查看代码
INLINE INT MERGE(INT U,INT V)
{
    IF(!U) RETURN V;
    IF(!V) RETURN U;
    INT P=++CNT;
    T[P].SUM=T[U].SUM+T[V].SUM;
    T[P].L=MERGE(T[U].L,T[V].L);
    T[P].R=MERGE(T[U].R,T[V].R);
    RETURN P;
}

权值线段树

类似于桶,存储数据出现过多少次。

点击查看代码
#define lson pos<<1
#define rson pos<<1|1

void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		tree[pos]=a[l];
		return;
	}
	build(lson,l,mid);
	build(rson,mid+1,r);
	tree[pos]=tree[lson]+tree[rson];
}//建树

void update(int pos,int l,int r,int k,int cnt)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		tree[pos]+=cnt;
		return;
	}
	if(k<=mid)
		update(lson,l,mid,k,cnt);
	else	
		update(rson,mid+1,r,k,cnt);
	tree[pos]=tree[lson]+tree[rson];
}//修改

int query(int pos,int l,int r,int k)
{
	int mid=(l+r)>>1;
	if(l==r)
		return tree[pos];
	if(k<=mid)
		return query(lson,l,mid,k);
	else
		return query(rson,mid+1,r,k);
}//查询 k 有多少个

int kth(int pos,int l,int r,int k)
{
	int mid=(l+r)>>1;
	if(l==r)
		return l;
	if(k<mid)
		return kth(rson,mid+1,r,k);
	else
		return kth(lson,l,mid,k-mid);
}//查询第 k 大值
模板题:逆序对(怎么还是
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
#define LL long long
const int N=500005;
int n,m,a[N],b[N];
int sum[N<<2];
void pushup(int p)
{
  sum[p]=sum[ls]+sum[rs];
}
void change(int p,int l,int r,int x)
{
  if(l==r){sum[p]++; return;}
  if(x<=mid) change(ls,l,mid,x);
  else change(rs,mid+1,r,x);
  pushup(p);
}//单点修改
LL query(int p,int l,int r,int x,int y)
{
  if(x<=l && r<=y) return sum[p];
  LL s=0;
  if(x<=mid) s+=query(ls,l,mid,x,y);
  if(y>mid) s+=query(rs,mid+1,r,x,y);
  return s;
}//区间查询
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++) 
        scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    LL s=0;
    for(int i=1; i<=n; i++)
    {
        int id=lower_bound(b+1,b+n+1,a[i])-b;
        change(1,1,n,id);
        s+=query(1,1,n,id+1,n);
    }
    printf("%lld\n",s);
}
SHOI2013 发牌

权值线段树与动态开点线段树板子,直接搬板子即可,注意改动为初始储存的值为 1,因为初始数列为 1~N 所以初始个数为 1

点击查看代码
#include<bits/stdc++.h>
#define INT int
#define SIGNED signed
#define MAIN main
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define USING using
#define IF if
#define FOR for
#define ELSE else
#define RETURN return
#define WHILE while
#define BREAK break
#define CONTINUE continue
#define VOID void
#define INLINE inline
#define CIN cin
#define COUT cout
#define LS P<<1
#define RS P<<1|1
#define MID ((L+R)>>1)
#define ENDL '\n'
#define LOWER_BOUND lower_bound
#define SORT sort
USING NAMESPACE STD;
NAMESPACE Watarai_Hinami
{
    INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
}
NAMESPACE Chongyun
{
    INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE Watarai_Hinami;
USING NAMESPACE Chongyun;
CONST INT n=1e5+10;
CONST INT INF=1e9+5;
STRUCT TREE
{
    INT L,R,SUM;
}T[n*32];
INT B[n],A[n],VAL[n];
INT FA[n],TO[n],NEXT[n];
INT ANS[n],RT[n];
INT SZ,TOT=1;
INLINE INT GETS(INT X)
{
    RETURN LOWER_BOUND(B+1,B+1+TOT,X)-B;
}
INLINE VOID UPDATE(INT &P,INT L,INT R,INT POS)
{
    IF(!P) P=++SZ;
    T[P].SUM++;
    IF(L==R)
        RETURN;
    IF(MID>=POS) UPDATE(T[P].L,L,MID,POS);
    ELSE UPDATE(T[P].R,MID+1,R,POS);
}
INLINE INT FIND(INT L,INT R,INT P,INT l)
{
	T[P].SUM--;
	IF(L==R) RETURN L;
	IF(l<=T[LS].SUM)
		RETURN FIND(L,MID,LS,l);
	ELSE RETURN FIND(MID+1,R,RS,l-T[LS].SUM);
}
INLINE INT MERGE(INT U,INT V)
{
    IF(!U) RETURN V;
    IF(!V) RETURN U;
    INT P=++SZ;
    T[P].SUM=T[U].SUM+T[V].SUM;
    T[P].L=MERGE(T[U].L,T[V].L);
    T[P].R=MERGE(T[U].R,T[V].R);
    RETURN P;
}
INLINE VOID DFS(INT P)
{
    FOR(INT K=NEXT[P];K;K=TO[K])
    {
        DFS(K);
        RT[P]=MERGE(RT[P],RT[K]);
    }
    ANS[P]=FIND(1,TOT,RT[P],VAL[P]+1);
    UPDATE(RT[P],1,TOT,VAL[P]);
}
INLINE VOID BUILD(INT P,INT L,INT R)
{
	IF(L==R){T[P].SUM=1;RETURN;}
	BUILD(LS,L,MID);
	BUILD(RS,MID+1,R);
	T[P].SUM=T[LS].SUM+T[RS].SUM;
}
SIGNED MAIN()
{
	INT N=READ();
	BUILD(1,1,N);
	INT X,Y=0;
	FOR(INT I=N;I>=1;--I)
	{
		X=READ();
		Y=(Y+X)%I;
		COUT<<FIND(1,N,1,Y+1)<<ENDL;
	}
}   
Promotion Counting

权值线段树+动态开点+合并。

建立一个权值线段树,在 dfs 过程中,对于每一个子节点把它的每一个子节点的线段树与它的线段树合并。答案就在当前线段树中查询比该节点的权值 \(val[x]\) 更大的值有多少个即可。

点击查看代码
#include<bits/stdc++.h>
#define INT int
#define SIGNED signed
#define MAIN main
#define USING using
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define IF if
#define ELSE else
#define RETURN return
#define WHILE while
#define BREAK break
#define CONTINUE continue
#define VOID void
#define INLINE inline
#define FOR for
#define CIN cin
#define COUT cout
#define LS P<<1
#define RS P<<1|1
#define ENDL '\n'
#define LOWER_BOUND lower_bound
#define SORT sort
USING NAMESPACE STD;
NAMESPACE Watarai_Hinami
{
    INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
    INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
}
NAMESPACE Chongyun
{
    INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
    INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE Watarai_Hinami;
USING NAMESPACE Chongyun;
CONST INT n=1e5+10;
CONST INT INF=1e9+5;
STRUCT TREE
{
    INT L,R,SUM;
}T[n*32];
INT B[n],A[n],VAL[n];
INT FA[n],TO[n],NEXT[n];
INT ANS[n],RT[n];
INT CNT,TOT=1;
INLINE INT GETS(INT X)
{
    RETURN LOWER_BOUND(B+1,B+1+TOT,X)-B;
}
INLINE VOID UPDATE(INT &P,INT L,INT R,INT POS)
{
    IF(!P) P=++CNT;
    T[P].SUM++;
    IF(L==R)
        RETURN;
    INT MID=L+R>>1;
    IF(MID>=POS) UPDATE(T[P].L,L,MID,POS);
    ELSE UPDATE(T[P].R,MID+1,R,POS);
}
INLINE INT FIND(INT P,INT L,INT R,INT l)
{
    IF(!P) RETURN 0;
    IF(L>=l)
        RETURN T[P].SUM;
    INT MID=L+R>>1;
    IF(MID>=l) RETURN FIND(T[P].L,L,MID,l)+FIND(T[P].R,MID+1,R,l);
    RETURN FIND(T[P].R,MID+1,R,l);
}
INLINE INT MERGE(INT U,INT V)
{
    IF(!U) RETURN V;
    IF(!V) RETURN U;
    INT P=++CNT;
    T[P].SUM=T[U].SUM+T[V].SUM;
    T[P].L=MERGE(T[U].L,T[V].L);
    T[P].R=MERGE(T[U].R,T[V].R);
    RETURN P;
}
INLINE VOID DFS(INT P)
{
    FOR(INT K=NEXT[P];K;K=TO[K])
    {
        DFS(K);
        RT[P]=MERGE(RT[P],RT[K]);
    }
    ANS[P]=FIND(RT[P],1,TOT,VAL[P]+1);
    UPDATE(RT[P],1,TOT,VAL[P]);
}
SIGNED MAIN()
{
    INT N=READ();
    FOR(INT I=1;I<=N;++I)
        B[I]=VAL[I]=READ();
    FOR(INT I=2;I<=N;++I)
    {
        FA[I]=READ();
        TO[I]=NEXT[FA[I]];
        NEXT[FA[I]]=I;
    }
    SORT(B+1,B+1+N);
    FOR(INT I=2;I<=N;++I)
        IF(B[I]!=B[TOT])
            B[++TOT]=B[I];
    FOR(INT I=1;I<=N;++I)
        VAL[I]=GETS(VAL[I]);
    DFS(1);
    FOR(INT I=1;I<=N;++I)
        COUT<<ANS[I]<<ENDL;
}   
雨天的尾巴

线段树合并板子题,经过 lxyt 的开导果断开贺😋😋😋

需要LCA求出两点之间公共祖先距离然后每个节点都建一颗线段树,大力合并即可。

因为线段树需要合并所以数组一定要开大,与洛谷上数据疯狂卡数组最终以一个很极端的大小过了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls p<<1
#define rs p<<1|1
const int N=1e7;
int n,m,maxx,tot;
int x[N],y[N],z[N],ans[N],root[N];
int l[N],r[N],dat[N],t[N];
int head[N],cnt;
struct node
{
    int next,to;
}e[N*5];
inline void add(int u,int v)
{
    e[++cnt].next=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}
int fa[N],top[N],size[N],son[N],deep[N];
void dfs1(int u,int f)
{
    size[u]=1;
    fa[u]=f;
    deep[u]=deep[f]+1;
    for(register int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f) continue;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
inline void dfs2(int u,int topf)
{
    top[u]=topf;
    if(!son[u]) return;
    dfs2(son[u],topf);
    for(register int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==topf || v==son[u] || top[v]) continue;
        dfs2(v,v);
    }
}
inline int lca(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    return deep[u]<deep[v] ? u : v;
}
inline void push_up(int p)
{
    if(dat[l[p]]>=dat[r[p]])
        dat[p]=dat[l[p]],t[p]=t[l[p]];
    else 
        dat[p]=dat[r[p]],t[p]=t[r[p]];
}
inline int find(int p,int L,int R,int pos,int val)
{
    if(!p) p=++tot;
    if(L==R)
    {
        dat[p]+=val;
        t[p]=L;
        return p;
    }
    int mid=(L+R)>>1;
    if(pos<=mid) l[p]=find(l[p],L,mid,pos,val);
    else r[p]=find(r[p],mid+1,R,pos,val);
    push_up(p);
    return p;
}
inline int merge(int p,int q,int L,int R)
{
    if(!q || !p) return p+q;
    if(L==R)
    {
        dat[p]+=dat[q];
        t[p]=L;
        return p;
    }
    int mid=(L+R)>>1;
    l[p]=merge(l[p],l[q],L,mid);
    r[p]=merge(r[p],r[q],mid+1,R);
    push_up(p);
    return p;
}
inline void fuck(int u)
{
    for(register int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(deep[v]>deep[u]) fuck(v),root[u]=merge(root[u],root[v],1,maxx);
        if(dat[root[u]]) ans[u]=t[root[u]];
    }
}
signed main()
{
    cin>>n>>m;
    for(register int i=1,u,v;i<n;++i)
    {
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(register int i=1;i<=m;++i)
    {
        cin>>x[i]>>y[i]>>z[i];
        maxx=max(z[i],maxx);
    }    
    for(register int i=1;i<=m;++i)
    {
        int LCA=lca(x[i],y[i]);
        root[x[i]]=find(root[x[i]],1,maxx,z[i],1);
        root[y[i]]=find(root[y[i]],1,maxx,z[i],1);
        root[LCA]=find(root[LCA],1,maxx,z[i],-1);
        if(fa[LCA]) root[fa[LCA]]=find(root[fa[LCA]],1,maxx,z[i],-1);
    }
    fuck(1);
    for(register int i=1;i<=n;++i)
        cout<<ans[i]<<'\n';
}

怎么我已经写了 2000 多行了?代码块这么多?

posted @ 2024-01-30 19:56  HS_xh  阅读(109)  评论(2编辑  收藏  举报
init();