1,cf Morning Jogging;2,acwing 239.奇偶游戏;3,acwing 1275.最大数;4,acwing 245.你能回答这些问题吗;
c++17 register 报错,多半是用了关键字做别的,比如time[],size[],这样的数组命名是不被允许的;但是会先给你报register 错,在说size is ambiguoous;所以注意了!!;
还有就是,提交cf选c++17,别选c++20;17能过,20不能过,。。就很烦;
1,Morning Jogging
题意:
给出n段路程,每段路程有m个走法,现在给m个人,要求把所有的路都走完,并且使他们的疲劳值之和最小;疲劳值(一个人走过的n段路程中最小的一段路程的数值);
eg:
2段路程,每段路3个走法,派3个人走完所有的路,疲劳值最小:
第一个人:2,5
第二个人:3,3
第三个人:4,1
所以min疲劳=2+3+1=6;
要求输出:
2 3 4
5 3 1
每一列对应一个人的走过的路;
题挺好做,就是要把输出搞定;
首先最小值必须在它出现的该段路径中,就是
2 3 0
0 0 1
这样先把最小值安排好,再去安排剩下的值,当然也要按出现的路段下标去放;
ps:一开始数组开的太小了,100*100明显是10000,我就是把a开成1010,一直tle,还不知为何。。冤死我了;
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define rep1(i,a,n) for(register ll i=a;i<n;i++)
#define rep2(i,a,n) for(register ll i=a;i<=n;i++)
#define per1(i,n,a) for(register ll i=n;i>a;i--)
#define per2(i,n,a) for(register ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define endl "\n"
#define lowbit(x) (-x&x)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=105;
int n,m;
struct ji
{
int x,y,key;
}a[N*N];
int ans[N][N];
int idx;
bool cmp(ji a,ji b)
{
return a.key<b.key;
}
void solve()
{
idx=0;
cin>>n>>m;
memset(ans,0,sizeof ans);
rep2(i,1,n)
rep2(j,1,m)
{
a[++idx].x=i;
a[idx].y=j;
cin>>a[idx].key;
}
sort(a+1,a+idx+1,cmp);
rep2(i,1,m)
{
ans[a[i].x][i]=a[i].key;
}
rep2(i,m+1,idx)
{
rep2(j,1,m)
{
if(ans[a[i].x][j]==0)
{
ans[a[i].x][j]=a[i].key;
break;
}
}
}
rep2(i,1,n)
{
rep2(j,1,m)cout<<ans[i][j]<<" ";
cout<<endl;
}
}
signed main()
{
quick_cin();
int T;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
2,奇偶游戏
和程序自动分析的传递类似,此题也可以传递,传递的是奇偶性,不过要想清楚几个等价关系;
这里用d[]数组来表示x与p[]的奇偶性,d[x]=0,表示奇偶性相同,d[x]=1,不同;
然后就是在find过程中保持奇偶性的更新,还是递归思想,回溯时更新;
还有就是离散化,给的数太大,但是又不多,所以映射到小的区间去做;
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define rep1(i,a,n) for(register ll i=a;i<n;i++)
#define rep2(i,a,n) for(register ll i=a;i<=n;i++)
#define per1(i,n,a) for(register ll i=n;i>a;i--)
#define per2(i,n,a) for(register ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define endl "\n"
#define lowbit(x) (-x&x)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e5+10;
unordered_map<int,int>hs;
int p[N],d[N];
int n,m,idx;
int get(int x)
{
if(!hs.count(x))hs[x]=++idx;
return hs[x];
}
int find(int x)
{
if(p[x]!=x)
{
int root=find(p[x]);
d[x]^=d[p[x]];
p[x]=root;
}
return p[x];
}
signed main()
{
quick_cin();
cin>>n>>m;
rep2(i,1,N)p[i]=i;
int ans=m;
rep2(i,1,m)
{
string c;int a,b;
cin>>a>>b>>c;
bool t=0;
if(c=="odd")t=1;
a=get(a-1),b=get(b);
int pa=find(a),pb=find(b);
if(pa==pb)
{
if(d[a]^d[b]!=t)
{
ans=i-1;
break;
}
}
else
{
p[pa]=pb;
d[pa]=d[a]^d[b]^t;
}
}
cout<<ans;
return 0;
}
3,线段树;
①pushup
②build():将一段区间初始化为线段树
③modify():修改一个点或者区间;单点:easy;区间:用到pushdown,hard;
④query:查询一段区间的信息;
⑤pushdown():
线段树是一颗满二叉树(除了最后一层):根节点是原区间,左孩子:[L,mid] ,右孩子:[mid+1, R] mid是
(l+r)/2 下取整;
和堆类似:用一维数组来存储线段树;
开空间一般开4n!!;最坏有2n-1+2n=4n-1个点;
build(int u ,int l,int r):
query():
查询的递归:
例题:最大数;
最多添加m个数,我们先开出m个数的数组,然后把添加有一个数看成修改那个位置的数;
线段树存储的值和题目有关,pushup是由子结点的值更新父节点,也和题目有关;
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define rep1(i,a,n) for(register ll i=a;i<n;i++)
#define rep2(i,a,n) for(register ll i=a;i<=n;i++)
#define per1(i,n,a) for(register ll i=n;i>a;i--)
#define per2(i,n,a) for(register ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define endl "\n"
#define lowbit(x) (-x&x)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=2e5+10;
struct ji
{
int l,r;
int v;
}tr[N*4];
int m,p;
void pushup(int u)
{
tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r)return;
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
int mid=tr[u].l+tr[u].r>>1;
int v=0;
if(l<=mid)v=query(u<<1,l,r);
if(r>mid)v=max(v,query(u<<1|1,l,r));
return v;
}
void modify(int u,int x,int v)
{
if(tr[u].l==x&&tr[u].r==x)
{
tr[u].v=v;
return;
}
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
signed main()
{
quick_cin();
int n=0,last=0;
cin>>m>>p;
build(1,1,m);
char c;int x;
while(m--)
{
cin>>c>>x;
if(c=='Q')
{
last=query(1,n-x+1,n);
cout<<last<<endl;
}
else
{
modify(1,n+1,((ll)last+x)%p);
n++;
}
}
return 0;
}
4,你能回答这些问题吗;
操作:
单点修改,区间查询;区间查询的是最大连续子段的和,所以node除了存l,r还有tmax,最大连续字段和(因题而异);
但是此题无法直接通过子节点求出父节点的tmax,所以需要辅助信息:每个区间的最大前缀和和最大后缀和;这样即可完成更新;
这样tmax=max(左儿子tmax,右儿子tmax,左儿子最大后缀和+右儿子最大前缀和)
即可完成tmax的更新,但是最大前缀和lmax,最大后缀和rmax也需要求;
拿lmax举例:
如果最大前缀和没有跨过mid,就和左儿子的lmax相等;
跨过mid,就是左儿子的和sum+右儿子的lmax;
最大后缀和同理;
但是又引出了sum,sum能不能右左右儿子直接得到呢?答案是可以的;就是左儿子的sum+右儿子的sum;
最终的node:
多通读理解几遍;
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define rep1(i,a,n) for(register ll i=a;i<n;i++)
#define rep2(i,a,n) for(register ll i=a;i<=n;i++)
#define per1(i,n,a) for(register ll i=n;i>a;i--)
#define per2(i,n,a) for(register ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define endl "\n"
#define lowbit(x) (-x&x)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=5e5+10;
int n,m;
struct node
{
int l,r;
int sum,lmax,rmax,tmax;
}tr[N*4];
int w[N];
void pushup(node &u,node &l,node &r)
{
u.sum=l.sum+r.sum;
u.lmax=max(l.lmax,l.sum+r.lmax);
u.rmax=max(r.rmax,r.sum+l.rmax);
u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
}
void pushup(int u)
{
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,r,w[r],w[r],w[r],w[r]};
return;
}
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int x,int v)
{
if(tr[u].l==x&&tr[u].r==x)tr[u]={x,x,v,v,v,v};
else
{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
node query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
else
{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid)return query(u<<1,l,r);
if(l>mid)return query(u<<1|1,l,r);
else
{
auto left=query(u<<1,l,r);
auto right=query(u<<1|1,l,r);
node ans;
pushup(ans,left,right);
return ans;
}
}
}
signed main()
{
quick_cin();
cin>>n>>m;
rep2(i,1,n)cin>>w[i];
build(1,1,n);
int k,x,y;
while(m--)
{
cin>>k>>x>>y;
if(k==1)
{
if(x>y)swap(x,y);
cout<<query(1,x,y).tmax<<endl;
}
else modify(1,x,y);
}
return 0;
}