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线段树的主要内容,如果未能解决你的问题,请参考以下文章