T1 树上的数

\(DFS\)一遍。结构体存边好像更快?

\(code:\)

T1

#include<bits/stdc++.h>
using namespace std; namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=5000010;
int n,m,a,b,f,q,x,y,sum,ans;
int idx,head[NN];
bool vis[NN];
struct edge{ int to,nex; }e[NN]; void dfs(int s){
if(vis[s]) return;
--sum; vis[s]=1;
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to) dfs(v);
} signed main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
sum=n=read(); m=read(); a=read(); b=read(); f=1;
for(int i=2;i<=n;++i){
e[++idx]=(edge){i,head[f]}; head[f]=idx;
f=((1ll*f*a+b)^19760817)%i+1;
}
q=read(); x=read(); y=read();
for(int i=1;i<=m;++i){
dfs(q); ans^=sum;
q=(((1ll*q*x+y)^19760817)^(i+1<<1))%(n-1)+2;
}
write(ans,'\n');
return 0;
}


T2 时代的眼泪

好像挺明显的换根\(DP\)。但我因为多组询问成功跑偏

考虑转换贡献,一个点的贡献即为它字数内权值小于它的点数,所有点的贡献之和即为答案。

首先不难求得\(1\)为根时的答案,接下来当根由\(x\)换成\(x\)的儿子\(y\)时,\(y\)的子树变为整棵树,\(x\)的子树变为以\(x\)为根时树中\(y\)子树外的部分。

可以树上主席树维护信息,但范围\(1e6\),主席树优秀的常数使它无法通过本题。可以用树状数组在\(DFS\)中记录遍历完子树后权值在某个范围的变化量来代替。

\(code:\)

T2

#include<bits/stdc++.h>
using namespace std; namespace IO{
auto read=[]()->int{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
};
void write(long long x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=1000010;
int n,q,u,w[NN],wn[NN],wf[NN];
long long f[NN];
int idx,head[NN];
struct edge{ int to,nex; }e[NN<<1];
int ext,has[NN];
auto add=[](int a,int b)->void{
e[++idx]=(edge){b,head[a]}; head[a]=idx;
e[++idx]=(edge){a,head[b]}; head[b]=idx;
}; namespace BIT{
int c[NN];
auto insert=[](int pos,int x)->void{ while(pos<=n+1){ c[pos]+=x; pos+=pos&-pos; } };
auto query=[](int pos)->int{ int res=0; while(pos){ res+=c[pos]; pos-=pos&-pos; } return res; };
void DFS(int s,int fa){
f[1]+=query(n+1)-query(w[s]);
insert(w[s],1);
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(v!=fa) DFS(v,s);
insert(w[s],-1);
}
void Dfs(int s,int fa){
wn[s]=-query(w[s]-1);
if(fa) wf[s]=-query(w[fa]-1);
insert(w[s],1);
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(v!=fa) Dfs(v,s);
wn[s]+=query(w[s]-1);
if(fa) wf[s]+=query(w[fa]-1);
}
} using namespace BIT; void dfs(int s,int fa){
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to) if(v!=fa){
f[v]=f[s]-wn[v]+query(w[v]-1)-wf[v];
dfs(v,s);
}
} signed main(){
freopen("tears.in","r",stdin);
freopen("tears.out","w",stdout);
n=read(); q=read();
for(int i=1;i<=n;i++)
w[i]=read(),has[i]=w[i];
sort(has+1,has+n+1); ext=unique(has+1,has+n+1)-has-1;
for(int i=1;i<=n;i++)
w[i]=lower_bound(has+1,has+ext+1,w[i])-has+1;
for(int a,b,i=1;i<n;i++)
a=read(),b=read(),add(a,b);
DFS(1,0); Dfs(1,0); dfs(1,0);
while(q--){
u=read();
printf("%lld\n",f[u]);
}
return 0;
}


T3 传统艺能

对这类问题有很经典的\(DP\)。设\(f_c\)表示以\(c\)结尾的本质不同子序列个数,有

\[f_c=1+\sum_{char}f_{char}
\]

这个转移是线性的,加上本题字符集只有\(3\),可以考虑矩阵优化。可以预处理出每个字符对应的转移矩阵,用线段树维护矩阵即可。

\(code:\)

T3

#include<bits/stdc++.h>
using namespace std; namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=100010,mod=998244353;
int n,m,x,y,op,num[NN];
char t,ch[NN];
void add(int& a,int b){ a=(a+b>=mod)?(a+b-mod):(a+b); } namespace segment_tree{
#define ld rt<<1
#define rd (rt<<1)|1
struct mat{
int s[4][4];
mat(){}
mat(int x){ memset(s,0,sizeof(s)); s[0][0]=s[1][1]=s[2][2]=s[3][3]=x; }
void print(){for(int i=0;i<=3;i++)for(int j=0;j<=3;j++)write(s[i][j],j==3?'\n':' ');puts("");}
mat operator*(const mat& a)const{
mat res=mat(0);
for(int i=0;i<=3;i++)
for(int k=0;k<=3;k++)
for(int j=0;j<=3;j++)
add(res.s[i][j],1ll*s[i][k]*a.s[k][j]%mod);
return res;
}
}st,ans,tmp,base[4],mt[NN<<2];
void init(){
st.s[0][0]=1;
base[1]=mat(1); base[2]=mat(1); base[3]=mat(1);
base[1].s[0][1]=base[1].s[1][1]=base[1].s[2][1]=base[1].s[3][1]=1;
base[2].s[0][2]=base[2].s[1][2]=base[2].s[2][2]=base[2].s[3][2]=1;
base[3].s[0][3]=base[3].s[1][3]=base[3].s[2][3]=base[3].s[3][3]=1;
}
void pushup(int rt){ mt[rt]=mt[ld]*mt[rd]; }
void build(int rt,int l,int r){
if(l==r) return mt[rt]=base[num[l]],void();
int mid=l+r>>1;
build(ld,l,mid);
build(rd,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int pos,int typ){
if(l==r) return mt[rt]=base[typ],void();
int mid=l+r>>1;
if(pos<=mid) update(ld,l,mid,pos,typ);
else update(rd,mid+1,r,pos,typ);
pushup(rt);
}
mat query(int rt,int l,int r,int opl,int opr){
if(l>=opl&&r<=opr) return mt[rt];
int mid=l+r>>1;
mat res=mat(1);
if(opl<=mid) res=res*query(ld,l,mid,opl,opr);
if(opr>mid) res=res*query(rd,mid+1,r,opl,opr);
return res;
}
} using namespace segment_tree; signed main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read(); m=read();
scanf("%s",ch+1);
for(int i=1;i<=n;i++)
num[i]=ch[i]-'A'+1;
init(); build(1,1,n);
while(m--){
op=read();
if(op==1){
x=read(); cin>>t;
update(1,1,n,x,t-'A'+1);
} else{
x=read(); y=read();
ans=st*query(1,1,n,x,y);
add(ans.s[0][1],ans.s[0][2]); add(ans.s[0][1],ans.s[0][3]);
printf("%d\n",ans.s[0][1]);
}
}
return 0;
}


T4 铺设道路

考虑通过差分将区间问题转化为单点问题。令\(b_i=d_{i-1}-d_i\),那么每次操作就是选取\(l,r\),使\(b_l-1,b_r+1\),代价为\((r-l)^2\),最终要将所有\(b\)置为\(0\)。(包括\(b_{n+1}\))

要使时间最短,就要保证每次操作都是有效的,即\(b_l>0,b_r<0\)。

可以维护一个队列,扫一遍\(b\),遇到\(b>0\)则插入队列,\(b<0\)则找队中元素将其消去。因为\(d\geq 0\),所以一定能消完。

要求最大值则优先消队尾元素,反之优先消队尾元素。

\(code:\)

T4

#include<bits/stdc++.h>
using namespace std; namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=100010,mod=998244353;
int n,m,x,y,op,num[NN];
char t,ch[NN];
void add(int& a,int b){ a=(a+b>=mod)?(a+b-mod):(a+b); } namespace segment_tree{
#define ld rt<<1
#define rd (rt<<1)|1
struct mat{
int s[4][4];
mat(){}
mat(int x){ memset(s,0,sizeof(s)); s[0][0]=s[1][1]=s[2][2]=s[3][3]=x; }
void print(){for(int i=0;i<=3;i++)for(int j=0;j<=3;j++)write(s[i][j],j==3?'\n':' ');puts("");}
mat operator*(const mat& a)const{
mat res=mat(0);
for(int i=0;i<=3;i++)
for(int k=0;k<=3;k++)
for(int j=0;j<=3;j++)
add(res.s[i][j],1ll*s[i][k]*a.s[k][j]%mod);
return res;
}
}st,ans,tmp,base[4],mt[NN<<2];
void init(){
st.s[0][0]=1;
base[1]=mat(1); base[2]=mat(1); base[3]=mat(1);
base[1].s[0][1]=base[1].s[1][1]=base[1].s[2][1]=base[1].s[3][1]=1;
base[2].s[0][2]=base[2].s[1][2]=base[2].s[2][2]=base[2].s[3][2]=1;
base[3].s[0][3]=base[3].s[1][3]=base[3].s[2][3]=base[3].s[3][3]=1;
}
void pushup(int rt){ mt[rt]=mt[ld]*mt[rd]; }
void build(int rt,int l,int r){
if(l==r) return mt[rt]=base[num[l]],void();
int mid=l+r>>1;
build(ld,l,mid);
build(rd,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int pos,int typ){
if(l==r) return mt[rt]=base[typ],void();
int mid=l+r>>1;
if(pos<=mid) update(ld,l,mid,pos,typ);
else update(rd,mid+1,r,pos,typ);
pushup(rt);
}
mat query(int rt,int l,int r,int opl,int opr){
if(l>=opl&&r<=opr) return mt[rt];
int mid=l+r>>1;
mat res=mat(1);
if(opl<=mid) res=res*query(ld,l,mid,opl,opr);
if(opr>mid) res=res*query(rd,mid+1,r,opl,opr);
return res;
}
} using namespace segment_tree; signed main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read(); m=read();
scanf("%s",ch+1);
for(int i=1;i<=n;i++)
num[i]=ch[i]-'A'+1;
init(); build(1,1,n);
while(m--){
op=read();
if(op==1){
x=read(); cin>>t;
update(1,1,n,x,t-'A'+1);
} else{
x=read(); y=read();
ans=st*query(1,1,n,x,y);
add(ans.s[0][1],ans.s[0][2]); add(ans.s[0][1],ans.s[0][3]);
printf("%d\n",ans.s[0][1]);
}
}
return 0;
}


2021.10.26考试总结[冲刺NOIP模拟16]的更多相关文章

  1. 2021.10.27考试总结[冲刺NOIP模拟17]

    T1 宝藏 发现每个数成为中位数的长度是关于权值单调的.线段树二分判断是否合法,单调指针扫即可. 考场上写了二分,平添\(\log\). \(code:\) T1 #include<bits/s ...

  2. 2021.7.15考试总结[NOIP模拟16]

    ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...

  3. 2016 10 26考试 NOIP模拟赛 杂题

    Time 7:50 AM -> 11:15 AM 感觉今天考完后,我的内心是崩溃的 试题 考试包 T1: 首先看起来是个贪心,然而,然而,看到那个100%数据为n <= 2000整个人就虚 ...

  4. Noip模拟83 2021.10.26

    T1 树上的数 有手就能在衡中$OJ$上过,但是$WaitingCoders$不行,就是这样 必须使用$O(n)$算法加上大力卡常,思路就是找子树内没更新的更新,更新过了直接$return$ 1 #i ...

  5. 2021.10.15考试总结[NOIP模拟77]

    \(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...

  6. 2021.10.18考试总结[NOIP模拟76]

    T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...

  7. 2021.10.12考试总结[NOIP模拟75]

    T1 如何优雅的送分 考虑式子的实际意义.\(2^{f_n}\)实际上就是枚举\(n\)质因子的子集.令\(k\)为这个子集中数的乘积,就可以将式子转化为枚举\(k\),计算\(k\)的贡献. 不难得 ...

  8. 2021.10.11考试总结[NOIP模拟74]

    T1 自然数 发现\(mex\)是单调不降的,很自然地想到用线段树维护区间端点的贡献. 枚举左端点,用线段树维护每个右端点形成区间的\(mex\)值.每次左端点右移相当于删去一个数. 记\(a_i\) ...

  9. 2021.10.9考试总结[NOIP模拟72]

    T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...

随机推荐

  1. 了解HTTP基本知识板块

    一.HTTP 协议概述 HTTP协议采用了请求/响座模型. 客户端向服务器发送-个请求,请求头包含请求的方法.URT..协议版本.以以 及包含请求修饰符.客户信息和内容的类似于MIME的消息结构. 服 ...

  2. 使用python快速搭建http服务

    python2语法:python -m SimpleHTTPServer python3语法:python -m http.server 在局域网中使用web去访问http:/IP:8000即可 可以 ...

  3. 机器学习——支持向量机SVM

    前言 学习本章节前需要先学习: <机器学习--最优化问题:拉格朗日乘子法.KKT条件以及对偶问题> <机器学习--感知机> 1 摘要: 支持向量机(SVM)是一种二类分类模型, ...

  4. .NET 6 中的HTTP 3支持

    dotnet团队官方博客发布了一篇HTTP3的文章:HTTP/3 support in .NET 6:https://devblogs.microsoft.com/dotnet/http-3-supp ...

  5. Django学习day09随堂笔记

    每日测验 """ 今日考题: 1.choices参数的应用场景有哪些,如何获取该字段的值 2.django是什么模型的框架,简述MTV与MVC模型 3.多对多表关系有几种 ...

  6. PHP中的日期相关函数(一)

    日期相关的操作函数是我们在日常的工作开发中最常接触到的功能.当然,大部分同学可能最多用到的就是 date() . time() 这两个函数,我们今天先不讲这两个函数,或许后面的文章也不太会讲它们,毕竟 ...

  7. web、app、小程序测试异同点

    http://www.spasvo.com/Company/news_show.asp?id=702 https://blog.csdn.net/weixin_43489515/article/det ...

  8. PHP 处理历史数据的伪代码

    <?php class a { protected static $Senior = [1, 2, 3]; protected static $NoSenior = [13, 14, 15, 1 ...

  9. nginx 添加ssl证书

    第一步: 获取linux的证书格式  .crt  .key 第二步: 在nginx中default.conf中再添加一个server 第三步: 内容举例如下: server { #这里开始 liste ...

  10. [转载]SELinux安全系统基础

    链接:http://www.cnblogs.com/xiaoluo501395377/archive/2013/05/26/3100444.html 本篇随笔将记录一下学习SELinux的一些心得与体 ...