12.11日记
CF数据结构
思路:偶数=偶+偶=奇+奇,而且,只有可能连续的偶对应偶,或者连续的奇对应奇,构成一个联通的长方形。所以预处理R,C每个值前面第一个与其奇偶性相反的数的位置。首先判断两个点是否奇偶性相同,如果不相同,则显然不连通。再看是否在同一个连通块里,用刚刚预处理的东西查询。
#include<bits/stdc++.h>
using namespace std;
#define db(x) cout<<#x<<":"<<x<<endl;
const int M=1e5+20;
int R[M],C[M],lastR[M],nextR[M],lastC[M],nextC[M];
int main(){
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
scanf("%d",&R[i]);
for(int i=1;i<=n;++i)
scanf("%d",&C[i]);
int nodd=0,neve=0;
for(int i=1;i<=n;++i)
if (R[i]&1)
nodd=i,lastR[i]=neve;
else
neve=i,lastR[i]=nodd;
nodd=neve=0;
for(int i=1;i<=n;++i)
if (C[i]&1)
nodd=i,lastC[i]=neve;
else
neve=i,lastC[i]=nodd;
nodd=neve=n+1;
for(int i=n;i>=1;--i)
if(R[i]&1)
nodd=i,nextR[i]=neve;
else
neve=i,nextR[i]=nodd;
nodd=neve=n+1;
for(int i=n;i>=1;--i)
if(C[i]&1)
nodd=i,nextC[i]=neve;
else
neve=i,nextC[i]=nodd;
for(int i=1;i<=q;++i){
int ra,ca,rb,cb;
scanf("%d%d%d%d",&ra,&ca,&rb,&cb);
if(R[ra]%2!=R[rb]%2)
printf("NO
");
else if (lastR[ra]<rb&&rb<nextR[ra]&&lastC[ca]<cb&&cb<nextC[ca])
printf("YES
");
else
printf("NO
");
}
return 0;
}
卡车加油题,只不过这里每次加油数量是一样的,而每次花费不一样,并且要求花费最小。那么就优先队列维护当前所有之前的体育馆的花费,每次取最小的喝饮料就可以了。
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+20;
#define LL long long
int pl[M];
priority_queue<int,vector<int>,greater<int> > q;
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%d",&pl[i]);
int inc;
scanf("%d",&inc);
LL ans=0;
bool v=true;
for(int i=1;i<=n;++i){
int c;
scanf("%d",&c);
q.push(c);
while(!q.empty()&&k<pl[i])
ans+=q.top(),q.pop(),k+=inc;
if (k<pl[i]){
v=false;
break;
}
}
if(v)
printf("%lld
",ans);
else
printf("-1
");
return 0;
}
主席树
- P3380:二逼平衡树
思路:其实就把带修主席树的那个树状数组套权值线段树加几个操作就可以了。
注意:
- 一定不要混用变量!!外面套i的时候里面就不要用i!!出现了好几次这种错误了。
- 一定要分清楚树状数组的大小(n)和权值线段树的大小(len)不要混用。
这个代码就很长了……
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define db(x) cout<<#x<<":"<<x<<endl;
const int M=5e4+20;
vector<int> lsh;
unordered_map<int,int> rev;
struct Opt{
int op,l,r,k;
Opt():op(0),l(0),r(0),k(0){}
}opt[M];
struct Tree{
int l,r,val;
Tree(int a=0,int b=0,int c=0):l(a),r(b),val(c){}
}v[M*200];
int a[M],cnt,len,now[M*2],n;
inline int lowbit(int x){return x&(-x);}
void operate(int &id,int l,int r,int pos,int x){
if (!id)
id=++cnt;
v[id].val+=x;
if (l==r)
return;
if (pos<=mid)
operate(v[id].l,l,mid,pos,x);
else
operate(v[id].r,mid+1,r,pos,x);
}
inline void BIToperate(int id,int pos,int k){
while(id<=n)
operate(id,1,len,pos,k),id+=lowbit(id);
}
int BITquery_sa(int l,int r,int ql,int qr,int k){//查询区间第k小
int Lnum=0;
if (l==r){
for(int i=qr;i;i-=lowbit(i))
now[i]=i;
for(int i=ql-1;i;i-=lowbit(i))
now[i]=i;
return l;
}
for(int i=qr;i;i-=lowbit(i))
Lnum+=v[v[now[i]].l].val;
for(int i=ql-1;i;i-=lowbit(i))
Lnum-=v[v[now[i]].l].val;
if (Lnum>=k){
for(int i=qr;i;i-=lowbit(i))
now[i]=v[now[i]].l;
for(int i=ql-1;i;i-=lowbit(i))
now[i]=v[now[i]].l;
return BITquery_sa(l,mid,ql,qr,k);
}
else{
for(int i=qr;i;i-=lowbit(i))
now[i]=v[now[i]].r;
for(int i=ql-1;i;i-=lowbit(i))
now[i]=v[now[i]].r;
return BITquery_sa(mid+1,r,ql,qr,k-Lnum);
}
}
int query_num(int idp,int l,int r,int pos){//查询值为pos的数有几个
if (!idp)
return 0;
if (l==r)
return v[idp].val;
if (pos<=mid)
return query_num(v[idp].l,l,mid,pos);
else
return query_num(v[idp].r,mid+1,r,pos);
}
int BITquery_num(int l,int r,int pos){
int ans=0;
for(int i=r;i;i-=lowbit(i))
ans+=query_num(i,1,len,pos);
for(int i=l-1;i;i-=lowbit(i))
ans-=query_num(i,1,len,pos);
return ans;
}
int query_rk(int idp,int l,int r,int pos){//查询比pos小的数有几个
if (!idp)
return 0;
if (l==r)
return 0;
if (pos<=mid)
return query_rk(v[idp].l,l,mid,pos);
else
return query_rk(v[idp].r,mid+1,r,pos)+v[v[idp].l].val;
}
int BITquery_rk(int l,int r,int pos){
int ans=0;
for(int i=r;i;i-=lowbit(i))
ans+=query_rk(i,1,len,pos);
for(int i=l-1;i;i-=lowbit(i))
ans-=query_rk(i,1,len,pos);
return ans;
}
int main(){
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]),lsh.push_back(a[i]);
for(int i=1;i<=m;++i){
scanf("%d",&opt[i].op);
if (opt[i].op==5||opt[i].op==4||opt[i].op==1)
scanf("%d%d%d",&opt[i].l,&opt[i].r,&opt[i].k),lsh.push_back(opt[i].k);
else if (opt[i].op==3)
scanf("%d%d",&opt[i].l,&opt[i].r),lsh.push_back(opt[i].r);
else
scanf("%d%d%d",&opt[i].l,&opt[i].r,&opt[i].k);
}
sort(lsh.begin(),lsh.end());
len=unique(lsh.begin(),lsh.end())-lsh.begin();
for(int i=0;i<len;++i)
rev[lsh[i]]=i+1;
for(int i=1;i<=n;++i)
now[i]=i;
cnt=n;
for(int i=1;i<=n;++i)
BIToperate(i,rev[a[i]],1);
for(int i=1;i<=m;++i)
if (opt[i].op==1)
printf("%d
",BITquery_rk(opt[i].l,opt[i].r,rev[opt[i].k])+1);
else if (opt[i].op==2)
printf("%d
",lsh[BITquery_sa(1,len,opt[i].l,opt[i].r,opt[i].k)-1]);
else if (opt[i].op==3)
BIToperate(opt[i].l,rev[a[opt[i].l]],-1),a[opt[i].l]=opt[i].r,BIToperate(opt[i].l,rev[a[opt[i].l]],1);
else if (opt[i].op==4){
int rk=BITquery_rk(opt[i].l,opt[i].r,rev[opt[i].k]);
if (rk==0)
printf("-2147483647
");
else
printf("%d
",lsh[BITquery_sa(1,len,opt[i].l,opt[i].r,rk)-1]);
}
else{
int rk=BITquery_rk(opt[i].l,opt[i].r,rev[opt[i].k]),
num=BITquery_num(opt[i].l,opt[i].r,rev[opt[i].k]);
int total=0;
for(int j=opt[i].r;j;j-=lowbit(j))
total+=v[j].val;
for(int j=opt[i].l-1;j;j-=lowbit(j))
total-=v[j].val;
if (rk==total||(rk==total-1&&num))
printf("2147483647
");
else if (num)
printf("%d
",lsh[BITquery_sa(1,len,opt[i].l,opt[i].r,rk+2)-1]);
else
printf("%d
",lsh[BITquery_sa(1,len,opt[i].l,opt[i].r,rk+1)-1]);
}
return 0;
}
总结
我知道,我最近,或者说我这半年,几乎一直都在做模板题。所谓我会了什么高级算法,其实也只是会板子题,不然金牌题还不是随手切?hhh
我知道,我必须要去做一些那种需要思考的题目,比如说刷CF。
但是,我一直觉得,应该循序渐进,打好基础。
板子题要是都做不好,那根本就没东西可想。
没关系,明年继续打,一年时间可以准备。虽然我最多只能在这一年时间里刷1000题(平均一天3道!),比不是wkc,cls等巨佬那种AC数量>4000。
但1000题,拿个金牌还是够的了的吧,或者cf橙名?
明日计划
- CF刷几道数据结构题
- 树链剖分
- 香港HI题。