10/2 模拟题+倍增lca+zkw线段树

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10/2 模拟题+倍增lca+zkw线段树相关的知识,希望对你有一定的参考价值。

P8289 [省选联考 2022] 预处理器

一道省选的模拟题,虽然说思路简单,但是实现的技巧真的很多。
总结一下:
1.当getline接收一整行数据时,注意在前一个接受的数据后用getchar接收换行符。
2.使用 stringstream可将接收的一整行数据用字符串数组存起来。
3.复习了字符串find函数和substr函数。
4.采用map实现字符串的映射,由于不可嵌套转换,因此转换后需要对字符串进行标记。

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int inf=1e18;
const int N=7e6+5;
const int mod=1e9+7;
bool cmp(int a,int b)return a>b;
int n,g;
map<string,pair<string,int> >mp;
string s;
string dfs(string s)

    string ss;
    for(int i=0,j;i<s.length();i+=j)
    
        for(j=0;(i+j<s.length())&&(s[i+j]>='0'&&s[i+j]<='9')||(s[i+j]>='a'&&s[i+j]<='z')||(s[i+j]>='A'&&s[i+j]<='Z')||(s[i+j]=='_');j++);
        if(j)
        
            string tmp=s.substr(i,j);
            if(mp.count(tmp)>0&&mp[tmp].second==0)
            
                //cout<<"fff  "<<tmp<<endl;
                mp[tmp].second=1;
                ss+=dfs(mp[tmp].first);
                mp[tmp].second=0;
            
            else
                ss+=tmp;
        
        else
        
            ss+=s[i++];
        
    
    return ss;

void solve()

    cin>>n;
    getchar();
    for(int i=1;i<=n;i++)
    
        getline(cin,s);
        stringstream str(s);
        vector<string>e;string s1;
        while (getline(str, s1, ' '))
            e.push_back(s1);
        //for(string x:e) cout<<x<<endl;
        if(e[0]=="#define")
        
            int g=s.find_first_of(' ',8);
            mp[e[1]]=make_pair(s.substr(g+1),0);
            cout<<endl;
            continue;
        
        else if(e[0]=="#undef")
        
            mp.erase(e[1]);
            cout<<endl;
            continue;
        
        cout<<dfs(s)<<endl;
    

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


P4427 [BJOI2018]求和

需要进行预处理。不然没法过5组hack数据。
一个处理小细节,因为第一层根节点深度为0,所以要从-1开始累加。
记录从根节点到该节点所有深度的k次方,最后询问的答案
val[x][k]+val[y][k]-val[g][k]-val[fa[g][0]],减去公共祖先的累加值。

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int inf=1e18;
const int N=7e5+5;
const int mod=998244353;
bool cmp(int a,int b)return a>b;
int n,x,y,k,dep[N],fa[N][20],val[N][55];
vector<int>e[N];
int qpow(int a,int b)

    int res=1;
    while(b)
    
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    
    return res;

void dfs(int u,int pre)

    dep[u]=dep[pre]+1;
    fa[u][0]=pre;
    for(int i=1;i<=50;i++)
        val[u][i]=(val[pre][i]+qpow(dep[u],i)%mod)%mod;
    for(int i=1;i<=19;i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int v:e[u])
        if(v!=pre) dfs(v,u);

int lca(int u,int v)

    if(dep[u]<dep[v]) swap(u,v);
    for(int i=19;i>=0;i--)
        if(dep[fa[u][i]]>=dep[v])
            u=fa[u][i];
    if(v==u) return v;
    for(int i=19;i>=0;i--)
    
        if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
    
    return fa[u][0];

void solve()

    cin>>n;
    for(int i=1;i<n;i++)
    
        int u,v;cin>>u>>v;
        e[u].push_back(v);e[v].push_back(u);
    
    dep[0]=-1;
    dfs(1,0);
    //for(int i=1;i<=n;i++) dep[i]--;
    int m;cin>>m;
    while(m--)
    
        cin>>x>>y>>k;
        int g=lca(x,y);
        int ans=(((val[x][k]+val[y][k])%mod-val[g][k]+mod)%mod-val[fa[g][0]][k]+mod)%mod;
        cout<<ans<<endl;
    

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


zkw线段树
大佬博客:https://www.cnblogs.com/bennettz/p/8320435.html (内带模板)
建树:先创建出分支节点,再根据具体要求赋值。

void build(int n)m=1;while((m<<=1)<n);m--;
void update(int x)while(x<<=1) mx[x]=max(mx[x<<1],mx[x<<1|1]);
void change_val(int x,int y) mx[x+m]=y;update(x+m);
int query_node(int x)return mx[x+m];

对于区间查询:挺难理解,写下注释
l向后退1,保证

int query(int l,int r)//区间查询 
    int ans=0;
    for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
        if(~l&1)ans=max(mx[l^1],ans);
        if(r&1)ans=max(mx[r^1],ans);
    
    return ans;

P4588 [TJOI2018]数学计算

使用线段树单点修改,若改点被除过,则直接不去乘。zkw线段树代码较短,容易记。


```cpp
#include <bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int inf=1e18;
const int N=7e5+5;
const int mod=998244353;
bool cmp(int a,int b)return a>b;
int Q,M,m,d[N];
void build(int n)

    m=1;while((m<<=1)<n);
    m--;
    for(int i=1;i<=m;i++) d[i]=1;
    for(int i=m+1;i<=m+n+1;i++) d[i]=1;

void solve()

    cin>>Q>>M;
    build(Q);
    for(int i=1;i<=Q;i++)
    
        int x,y,p;cin>>x>>y;
        if(x==1)
            p=m+i,d[p]=y%M;
        else
            p=m+y,d[p]=1;
        while(p>>=1)
            d[p]=d[p<<1]*d[p<<1|1]%M;
        cout<<d[1]<<endl;
    

signed main()

    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;


以上是关于10/2 模拟题+倍增lca+zkw线段树的主要内容,如果未能解决你的问题,请参考以下文章

P5344 XR-1逛森林[倍增优化建图,zkw线段树优化spfa]

树上倍增求LCA

[bzoj5379]Tree_dfs序_线段树_倍增lca

蓝书4.1-4.4 树状数组RMQ问题线段树倍增求LCA

天天爱跑步:桶(就是数组)/权值线段树(没打)

小X的佛光 NOIP模拟赛 倍增LCA 树结构