主席树 学习报告

文章目录

  • 前言
  • 可持久化线段树
    • 代码
  • 区间第k大
    • 代码
  • 练习
    • 粟粟的书架
      • 代码
    • 森林
      • 代码
    • 任务查询系统
      • 代码
    • 列队
      • 代码

前言

主席树,全称是可持久化权值线段树
利用r和l-1两棵权值线段树作差得到[l,r]的信息
从而解决各种问题
排名这方面功能极其强大

可持久化线段树

学主席树之前,我们当然要先掌握这个东西啦
其实也很简单,就是只增加每个版本信息相对于上一个版本不同的结点,其他结点保留
这样每次修改只会增加log个结点
保证空间复杂度的正确性
然后还有一个技巧是动态开点
就是每次给新点分配个编号,左右儿子拿数组(或指针)指一下就行了

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid (l+r>>1)
const int N=1e6+100;
int n,m,tot;
int r[N],a[N];
struct node{int ls,rs,val;
}tr[N*20];
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].val=tr[tr[x].ls].val+tr[tr[x].rs].val;
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].val=a[l];return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].val=v;return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
int ask(int x,int l,int r,int p){if(l==r) return tr[x].val;if(p<=mid) return ask(tr[x].ls,l,mid,p);else return ask(tr[x].rs,mid+1,r,p);
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);build(r[0],1,n);int t,op,pl,v;for(int i=1;i<=m;i++){scanf("%d%d%d",&t,&op,&pl);if(op==1){scanf("%d",&v);r[i]=r[t];update(r[i],1,n,pl,v);}else{r[i]=r[t];printf("%d\n",ask(r[i],1,n,pl));}}return 0;
}

区间第k大

然后就是这个主席树的经典问题啦
首先从前往后建n个版本的权值线段树
利用前言说的两棵树做差的思想进行查找
就迎刃而解了

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid (l+r>>1)
const int N=1e6+100;
int n,m,tot;
int r[N],a[N];
struct node{int ls,rs,val;
}tr[N*20];
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].val=tr[tr[x].ls].val+tr[tr[x].rs].val;
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].val=0;return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].val+=v;return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
int q[N];
int find(int x,int y,int l,int r,int k){if(l==r) return l;if(tr[tr[y].ls].val-tr[tr[x].ls].val>=k){return find(tr[x].ls,tr[y].ls,l,mid,k);}else return find(tr[x].rs,tr[y].rs,mid+1,r,k-(tr[tr[y].ls].val-tr[tr[x].ls].val));
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]),q[i]=a[i];sort(q+1,q+1+n);int cnt=unique(q+1,q+1+n)-q-1;build(r[0],1,n);for(int i=1;i<=n;i++){a[i]=lower_bound(q+1,q+1+cnt,a[i])-q;r[i]=r[i-1];update(r[i],1,n,a[i],1);}int x,y,k;for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&k);printf("%d\n",q[find(r[x-1],r[y],1,n,k)]);}return 0;
}

练习

然后就是几道练习题!OvO

粟粟的书架

传送门
贪心的想,肯定要从大往小拿
这个二维的范围才到200,做一下前缀和二分答案即可
一维是今天的内容了,其实也和区间第k大差不多
就是先可着右儿子拿,不够再往左走
这样就可以啦
还是比较裸
记得判一下无解

代码

//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid ((l+r)>>1)
const int N=5e5+100;
int n,m,ask,tot;
int r[N],a[N];
int q[N];
struct node{int ls,rs,sum,siz;
}tr[N*25];
int ceil(int x,int y){return x%y==0?x/y:x/y+1;
}
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz;
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].sum=tr[x].siz=0;return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].siz++;tr[x].sum+=q[l];return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
int find(int x,int y,int l,int r,int k){
//	printf("l=%d r=%d lft=%d\n",q[l],q[r],k);if(l==r) return ceil(k,q[l]);if(tr[tr[y].rs].sum-tr[tr[x].rs].sum>=k){return find(tr[x].rs,tr[y].rs,mid+1,r,k);}else return tr[tr[y].rs].siz-tr[tr[x].rs].siz+find(tr[x].ls,tr[y].ls,l,mid,k-(tr[tr[y].rs].sum-tr[tr[x].rs].sum));
}
int x1,y1,x2,y2,h;
void work1(){n=m;for(int i=1;i<=n;i++) scanf("%d",&a[i]),q[i]=a[i];sort(q+1,q+1+n);int cnt=unique(q+1,q+1+n)-q-1;build(r[0],1,cnt);for(int i=1;i<=n;i++){a[i]=lower_bound(q+1,q+1+cnt,a[i])-q;r[i]=r[i-1];update(r[i],1,cnt,a[i],1);}for(int i=1;i<=ask;i++){scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);if(tr[r[y2]].sum-tr[r[y1-1]].sum<h) printf("Poor QLW\n");else printf("%d\n",find(r[y1-1],r[y2],1,cnt,h));}
}
int sum[205][205][1020],num[205][205][1020];
int x[205][205];
int ask_sum(int x1,int y1,int x2,int y2,int k){if(k>1000) return 0;return sum[x2][y2][k]-sum[x1-1][y2][k]-sum[x2][y1-1][k]+sum[x1-1][y1-1][k];
}
int ask_num(int x1,int y1,int x2,int y2,int k){if(k>1000) return 0;return num[x2][y2][k]-num[x1-1][y2][k]-num[x2][y1-1][k]+num[x1-1][y1-1][k];
}
void work2(){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) scanf("%d",&x[i][j]);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=0;k<=1000;k++){sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(x[i][j]>=k)*x[i][j];num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(x[i][j]>=k);	}}}for(int i=1;i<=ask;i++){scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);int st=0,ed=1000;while(st<ed){int mmid=(st+ed+1)>>1;if(ask_sum(x1,y1,x2,y2,mmid)>=h) st=mmid;else ed=mmid-1;}if(st==0) printf("Poor QLW\n");else printf("%d\n",ask_num(x1,y1,x2,y2,st+1)+ceil(h-ask_sum(x1,y1,x2,y2,st+1),st));}
}
int main(){scanf("%d%d%d",&n,&m,&ask);if(n==1) work1();else work2();return 0;
}

森林

传送门
本题的两个要求:

  1. 树合并
  2. 查询第k大

第一个显然要用LCT (然鹅我不会)
第二个就是主席树了
但是…鱼和熊掌不可兼得啊
我们必须舍弃一个的优秀复杂度
考虑到诸多因素 (including我不会LCT)
我们想到可以用启发式合并的方式把暴力合并的复杂度优化到log
合并时dfs维护一下倍增数组和到根的权值线段树就行了

注意:倍增数组更新时无意义的一定要全部赋值成0!
(不然它在更新前可能是有值的)

启发式合并这东西是真的香
啥算法都没有就直接变暴力为log
一定要有这根弦

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid ((l+r)>>1)
const int N=8e4+100;
int n,m,ask,tot;
int r[N],a[N];
int q[N];
struct edge{int to,nxt;
}p[N<<2];
int fi[N],ccnt=-1;
int cnt;
void addline(int x,int y){p[++ccnt]=(edge){y,fi[x]};fi[x]=ccnt;
}
struct node{int ls,rs,siz;
}tr[80001*500];
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz;
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].siz=0;return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].siz+=v;return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
int lst,x,y,w;
int pl[N][20],mi[20];
int vis[N],dep[N],siz[N],root[N];
void dfs(int x,int f){vis[x]=1;root[x]=f?root[f]:x;siz[x]=1;r[x]=r[f];update(r[x],1,cnt,a[x],1);pl[x][0]=f;for(int i=1;i<=17;i++){pl[x][i]=pl[pl[x][i-1]][i-1];}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dep[to]=dep[x]+1;//合并前要先赋一下y的dep!dfs(to,x);siz[x]+=siz[to]; //还要更新siz! }
}
int lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int k=17;k>=0;k--){if(dep[x]-mi[k]<dep[y]) continue;x=pl[x][k];}if(x==y) return x;for(int k=17;k>=0;k--){if(pl[x][k]==pl[y][k]) continue;x=pl[x][k];y=pl[y][k];}return pl[x][0];
}
int find(int x,int y,int u,int v,int l,int r,int k){if(l==r) return q[l];int s=tr[tr[x].ls].siz+tr[tr[y].ls].siz-tr[tr[u].ls].siz-tr[tr[v].ls].siz;if(s>=k) return find(tr[x].ls,tr[y].ls,tr[u].ls,tr[v].ls,l,mid,k);else return find(tr[x].rs,tr[y].rs,tr[u].rs,tr[v].rs,mid+1,r,k-s);
}
int main(){
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);memset(fi,-1,sizeof(fi));mi[0]=1;for(int i=1;i<=17;i++) mi[i]=mi[i-1]<<1;int o;scanf("%d",&o);scanf("%d%d%d",&n,&m,&ask);for(int i=1;i<=n;i++) scanf("%d",&a[i]),q[i]=a[i];sort(q+1,q+1+n);cnt=unique(q+1,q+1+n)-q-1;for(int i=1;i<=n;i++) a[i]=lower_bound(q+1,q+1+cnt,a[i])-q;for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);addline(x,y);addline(y,x);}build(r[0],1,cnt);for(int i=1;i<=n;i++){if(!vis[i]) dfs(i,0);}char op;for(int i=1;i<=ask;i++){scanf(" %c%d%d",&op,&x,&y);if(op=='Q'){scanf("%d",&w);x^=lst;y^=lst;w^=lst;if(x>n||y>n||w>n) break;int anc=lca(x,y);
//			printf("lca=%d\n",anc);lst=find(r[x],r[y],r[anc],r[pl[anc][0]],1,cnt,w);printf("%d\n",lst);}else{x^=lst;y^=lst;if(x>n||y>n) break;addline(x,y);addline(y,x);int xx=root[x],yy=root[y];if(siz[xx]<siz[yy]){swap(xx,yy);swap(x,y);}siz[xx]+=siz[yy];dep[y]=dep[x]+1;dfs(y,x);}}return 0;
}

任务查询系统

传送门
比较水啦
直接离线下来在两个端点修改一下对应的权值线段树即可
查询甚至都不用做差了

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid ((l+r)>>1)
const int N=1e5+100;
int n,m,tot;
int r[N],a[N];
int q[N];
int num;
struct node{int ls,rs,siz;ll sum;
}tr[N*100];
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz;tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].siz=tr[x].sum=0;return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].siz+=v;tr[x].sum+=v*q[l];return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
ll find(int x,int l,int r,int k){
//	printf("x=%d l=%d r=%d siz=%d sum=%d\n",x,l,r,tr[x].siz,tr[x].sum);if(l==r) return 1ll*min(k,tr[x].siz)*q[l];if(tr[tr[x].ls].siz>=k) return find(tr[x].ls,l,mid,k);else return tr[tr[x].ls].sum+find(tr[x].rs,mid+1,r,k-tr[tr[x].ls].siz);
}
struct ask{int pl,v,op;bool operator < (const ask y)const{return pl<y.pl;}
}p[N<<1];
int cnt;
int x[N],y[N],val[N];
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d%d%d",&x[i],&y[i],&val[i]);q[i]=val[i];}sort(q+1,q+1+n);num=unique(q+1,q+1+n)-q-1;for(int i=1;i<=n;i++){val[i]=lower_bound(q+1,q+1+num,val[i])-q;p[++cnt]=(ask){x[i],val[i],1};p[++cnt]=(ask){y[i]+1,val[i],-1};}sort(p+1,p+1+cnt);build(r[0],1,num);int pl=1;for(int t=1;t<=n;t++){r[t]=r[t-1];while(p[pl].pl==t){update(r[t],1,num,p[pl].v,p[pl].op);pl++;}}ll pre=1,t,a,b,c,w;for(int i=1;i<=m;i++){scanf("%lld%lld%lld%lld",&t,&a,&b,&c);w=(1ll*pre%c*a+b)%c+1;
//		printf("w=%d\n",w);pre=find(r[t],1,num,w);printf("%lld\n",pre);}return 0;
}

列队

传送门

显然让学生相对位置不变的对号入座可以是一种最优方案
又由于学生位置两两不同(关键条件!)
所以代价一定是左边一部分是按k+s-1-as
右边一部分是相反数
所以我们只要找到那个分界点就行了
我的思路是每次递归找第k大判断只往左右儿子的一条递归
这样是两个log的
只有70pts
正解是直接放心大胆算,只要不能确定这一整段的符号就直接往两侧递归
很多人说这就是一个log,但显然它并非递归后一定有一边直接返回
但考虑到k的位置是连续变化的十分稠密,应该很接近单log了
肯定比两个log好
我就是被楼房重建搞魔怔了

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define mid ((l+r)>>1)
const int N=1e6+100;
const int o=1e6;
int n,m,tot;
int r[N],a[N];
int q[N];
int num;
struct tree{int ls,rs,siz,mx;ll sum;
}tr[N*30];
int copy(int x){tr[++tot]=tr[x];return tot;
}
void pushup(int x){tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz;tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;tr[x].mx=max(tr[tr[x].ls].mx,tr[tr[x].rs].mx);
}
void build(int &x,int l,int r){x=++tot;if(l==r){tr[x].siz=tr[x].sum=0;return;}build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);pushup(x);
}
void update(int &x,int l,int r,int p,int v){x=copy(x);if(l==r){tr[x].siz+=v;tr[x].sum+=v*l;tr[x].mx=l;return;}if(p<=mid) update(tr[x].ls,l,mid,p,v);else update(tr[x].rs,mid+1,r,p,v);pushup(x);
}
struct node{int num;ll tot;
};
ll xigema(int x){x--;return 1ll*(1+x)*x/2;
}
node find(int x,int y,int l,int r,int k,int num){if(tr[y].siz-tr[x].siz==0) return (node){0,0};if(k+num-1<=l) return (node){tr[y].siz-tr[x].siz,tr[y].sum-tr[x].sum};else if(k>=r) return (node){0,-(tr[y].sum-tr[x].sum)};else{int s=tr[tr[y].ls].siz-tr[tr[x].ls].siz;node a=find(tr[x].ls,tr[y].ls,l,mid,k,s);node b=find(tr[x].rs,tr[y].rs,mid+1,r,k+s,num-s);return (node){a.num+b.num,a.tot+b.tot};}
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);build(r[0],1,o);for(int i=1;i<=n;i++){r[i]=r[i-1];update(r[i],1,o,a[i],1);}int x,y,k;for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&k);int c=y-x+1;node ans=find(r[x-1],r[y],1,o,k,c);ll res=ans.tot-(xigema(c)-2*xigema(c-ans.num))+1ll*(c-2*ans.num)*k;//printf("num=%d tot=%lld\n",ans.num,ans.tot);printf("%lld\n",res);}return 0;
}
/*
5 5
1 5 7 6 2
1 5 2
1 5 3
1 3 9
2 4 2
3 5 5
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318170.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Star Way To Heaven (prim最小生成树) // [ NOIP提高组 2014]飞扬的小鸟(DP)

文章目录T1&#xff1a;Star Way To Heaven题目题解代码实现T2&#xff1a;飞扬的小鸟题目题解代码实现T1&#xff1a;Star Way To Heaven 题目 小 w 伤心的走上了 Star way to heaven。 到天堂的道路是一个笛卡尔坐标系上一个 n*m 的长方形通道 顶点在 (0,0) 和 (n,m) 。 小…

CF1043E Train Hard, Win Easy

CF1043E Train Hard, Win Easy 题意&#xff1a; n个人有Ai和Bi两个属性&#xff0c;给出m个关系&#xff1a;xi yi表示xi和yi不能配对 i,j两人规定匹配的价值为min (Ai Bj , Bi Aj ) 回答出每个人跟所有人配对&#xff08;除开不能和自己匹配的人&#xff09;的价值总和 …

P7887-「MCOI-06」Existence of Truth【构造】

正题 题目连接:https://www.luogu.com.cn/problem/P7887?contestId52021 题目大意 给出三个长度为nnn的序列xi,yi,zix_i,y_i,z_ixi​,yi​,zi​&#xff0c;求一个序列aaa满足0≤ai<10970\leq a_i<10^970≤ai​<1097且 xi(∑j1iaj)yi(∑jinaj)≡zi(mod1097)x_i\lef…

IdentityServer4-客户端的授权模式原理分析(三)

在学习其他应用场景前&#xff0c;需要了解几个客户端的授权模式。首先了解下本节使用的几个名词Resource Owner&#xff1a;资源拥有者&#xff0c;文中称“user”&#xff1b;Client为第三方客户端&#xff1b;Authorization server为授权服务器&#xff1b;redirection URI&…

【做题记录】[NOIP2011 提高组] 观光公交

P1315 [NOIP2011 提高组] 观光公交 我们想在 \(k\) 次加速每一次都取当前最优的方案加速。 考虑怎样计算对于每一条边如果在当前情况下使用加速器能够使答案减少的大小。 如果当前到达某个点时已经有人在等待了&#xff0c;那么加速这个点以前的边能够让这个点下车的人距离减少…

[2019 牛客CSP-S提高组赛前集训营4题解] 复读数组(数论)+ 路径计数机(数上DP)+ 排列计数机(线段树+二项式定理)

文章目录T1&#xff1a;复读数组题目题解代码实现T2&#xff1a;路径计数机题目题解代码实现T3&#xff1a;排列计数机题目题解CODET1&#xff1a;复读数组 题目 有一个长为nk的数组&#xff0c;它是由长为n的数组A1,A2,…,An重复k次得到的。 定义这个数组的一个区间的权值为…

模板:(多重)哈希

前言 还在为不想写双哈希又怕哈希冲突挂掉发愁吗&#xff1f; 来这里&#xff0c;满足你的一切梦想&#xff01; 哈希还有模板&#xff1f; 其实就是把相关的函数和数组打包到一个结构体里 但是针心方便啊&#xff01;&#xff01;&#xff01; 如果想双哈希的话&#xff0c;定…

CF1183H Subsequences (hard version)

题意&#xff1a; 长度为n的字符串S&#xff0c;现在要找出k个不同的子序列&#xff0c;使得这些序列的总价值最低 一个序列的价值等于删去的字符长度&#xff08;空串也算子序列&#xff09; 1≤n≤100,1≤k≤1012 题解&#xff1a; 一看就是dp&#xff0c;我们先想想串a可…

P7888-「MCOI-06」Distinct Subsequences【dp】

正题 题目大意 给出一个长度为nnn的字符串aaa&#xff0c;求它的所有子序列的本质不同子序列个数。 1≤n≤1061\leq n\leq 10^61≤n≤106 解题思路 考虑每个子序列产生的贡献&#xff0c;为了防止算重我们一个只统计走子序列自动机上的边的子序列&#xff0c;也就是说对于TTT…

微软携手 Docker 打造 CNAB,分布式应用来了!

微软中国MSDN 前天Microsoft Connect(); 2018发布的众多最新科技&#xff0c;都让全球开发者惊艳不已。其中一项最令开发者瞩目并迫不及待——微软联合Docker发布了云本地应用捆绑包&#xff08;Cloud Native Application Bundle&#xff0c;以下简称CNAB&#xff09;&#xff…

9.4 模拟

前言 175分 60100150 T3和T4做的不好 T4没有理解题目的意思…qwq T3暴力似乎挂了… 但T1和T2还是不戳的 T1打表找规律的方法也许更为有效 考场 先看题。 药丸。。 T3、4甚至根本没有看懂… T1和T2也感觉挺玄乎的 有一种爆零的预感 8&#xff1a;10 先看T1 推了推似乎还是有…

P4135 作诗

P4135 作诗 题意&#xff1a; 给定 n 个不大于 c 的正整数 a1…an 和 m 组询问&#xff0c;每次问 [l,r] 中有多少个数出现正偶数次。 对于每次询问&#xff1a; 设上一个询问的答案为 ans&#xff08;第一个询问时 ans0&#xff09;&#xff0c;令L(lans)mod n1&#xff0c;…

[C++]试一试结构体struct node的构造函数

可直接点击跳转到构造函数处结构体概念定义结构体定义结构体及结构体变量结构体变量的特点成员调用成员函数调用结构体的构造函数Upd1Upd2Upd3结构体概念 在实际问题中&#xff0c;一组数据往往具有不同的数据类型。 例如&#xff1a;人口大普查时&#xff0c;需要记录每一个人…

CSP-S 2021 退役记

写的比较草率&#xff0c;但的确是真实感受。 10.23 回寝室前敲了一个 dinic 板子&#xff0c;觉得不会考。。。 10.24 8:00 起床&#xff0c;还好今天宿管不在&#xff0c;可以起的晚一点。 吃了早饭来机房颓废。 10:00 似乎考前反而不知道该如何复习了&#xff0c;翻了翻以前…

Ybtoj-排列计数【矩阵乘法,分块幂】

正题 题目链接:http://noip.ybtoj.com.cn/contest/596/problem/1 题目大意 TTT组询问给出nnn求有多少个nnn的排列满足第一个是111并且相邻的差不超过222。 1≤T≤106,1≤n≤1091\leq T\leq 10^6,1\leq n\leq 10^91≤T≤106,1≤n≤109 解题思路 考虑一下如果我们要不断向前填满…

[多校联考-西南大学附中]切面包(线段树/概率与期望)+ Slow Path Finding Algorithm(拓扑排序/DP)+ 分数转化(数论)

文章目录T1&#xff1a;分数转换题目题解代码实现T2&#xff1a;Slow Path Finding Algorithm题目题解代码实现T3&#xff1a;切面包题目题解代码实现T1&#xff1a;分数转换 题目 Time limit: 1.5 seconds Memory limit: 512 megabytes 给定一个十进制小数&#xff0c;请你…

P3992 [BJOI2017]开车

P3992 [BJOI2017]开车 题意&#xff1a; 题解&#xff1a; 我们要先将问题转换 圈是车&#xff0c;x是加油站。红色部分为车移动的路线 数组a是车数量的前缀和 数组b是加油站的前缀和 而a[i]与b[i]的差的绝对值就是对应的红色路被走的次数 现在车发生位置移动&#xff0c;b数…

IdentityServer4-MVC+Hybrid实现Claims授权验证(四)

上节IdentityServer4-客户端的授权模式原理分析&#xff08;三&#xff09;以对话形式&#xff0c;大概说了几种客户端授权模式的原理&#xff0c;这节重点介绍Hybrid模式在MVC下的使用。且为实现IdentityServer4从数据库获取User进行验证&#xff0c;并对Claim进行权限设置打下…

9.05 模拟

文章目录前言考场复盘T2T4总结前言 290分 1003010060 整体来说还不错&#xff0c;没有挂分 但是T2应该可以拿到值域[1,000]的第二档写到60分的 一部分原因也是给T2的时间有点少 &#xff08;十分钟&#xff09; 本次第一次尝试了在考场上对拍 效果还是不错的&#xff0c;并不会…

李超线段树

李超线段树可以用来维护平面上的线段(但是要求 \(x\) 或 \(y\) 其中一维比较小&#xff0c;在 \(10^5\) 及以内)。 称一条线段能成为区间 \([l,r]\) 中的最优线段&#xff0c;当且仅当&#xff1a; 该线段的定义域完整覆盖了区间 \([l,r]\) &#xff1b; 该线段在区间中点处最…