12.7日记
线段树
- POJ3667:区间修改+询问最靠左的长度为x的连续区间。
思路和上个题差不多,只不过这里是区间修改,所以只能用线段树了。这里注意如果是直接修改值的话,lazy标记的初始值必须是-1,因为可以改成0。出了点小错误,以后写代码还是要仔细。
#include<cstdio>
#include<algorithm>
#define mid (l+r)/2
using namespace std;
const int M=5e4+20;
int lm[4*M],rm[4*M],mm[4*M],col[4*M],lazy[4*M];
inline void pushup(int id,int l,int r){
if (col[id*2]==1)
lm[id]=lm[id*2]+lm[id*2+1];
else
lm[id]=lm[id*2];
if (col[id*2+1]==1)
rm[id]=rm[id*2+1]+rm[id*2];
else
rm[id]=rm[id*2+1];
mm[id]=max(max(mm[id*2],mm[id*2+1]),rm[id*2]+lm[id*2+1]);
if (mm[id]==0)
col[id]=0;
else if (mm[id]==r-l+1)
col[id]=1;
else
col[id]=-1;
}
inline void pushdown(int id,int l,int r){
if (lazy[id]==0)
lazy[id*2]=lazy[id*2+1]=lm[id*2]=lm[id*2+1]=rm[id*2]=rm[id*2+1]=mm[id*2]=mm[id*2+1]=col[id*2]=col[id*2+1]=0;
else if (lazy[id]==1)
lazy[id*2]=lazy[id*2+1]=1,
lm[id*2]=rm[id*2]=mm[id*2]=mid-l+1,
lm[id*2+1]=rm[id*2+1]=mm[id*2+1]=r-mid,
col[id*2]=col[id*2+1]=1;
lazy[id]=-1;
}
void build(int id,int l,int r){
col[id]=1,lm[id]=rm[id]=mm[id]=r-l+1,lazy[id]=-1;
if (l==r)
return;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id,l,r);
}
void operate(int id,int l,int r,int ql,int qr,int x){
if (ql<=l&&r<=qr){
if (x)
lm[id]=rm[id]=mm[id]=r-l+1,
col[id]=lazy[id]=1;
else
lm[id]=rm[id]=mm[id]=col[id]=lazy[id]=0;
return;
}
pushdown(id,l,r);
if(ql<=mid)
operate(id*2,l,mid,ql,qr,x);
if (mid<qr)
operate(id*2+1,mid+1,r,ql,qr,x);
pushup(id,l,r);
}
int query(int id,int l,int r,int x){//第一个长度至少为x的区间的左端点
pushdown(id,l,r);
if (mm[id*2]>=x)
return query(id*2,l,mid,x);
if (rm[id*2]+lm[id*2+1]>=x)
return mid-rm[id*2]+1;
if (mm[id*2+1]>=x)
return query(id*2+1,mid+1,r,x);
return 0;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
build(1,1,n);
for(int i=1;i<=m;++i){
int op;
scanf("%d",&op);
if (op==1){
int x;
scanf("%d",&x);
int ca=query(1,1,n,x);
if (ca)
operate(1,1,n,ca,ca+x-1,0);
printf("%d
",ca);
}
else{
int x,y;
scanf("%d%d",&x,&y);
operate(1,1,n,x,x+y-1,1);
}
}
}
return 0;
}
- HDU3308:单点修改+区间查询最长连续上升子序列
思路一样,只不过这里查询的时候,需要对两个区间进行合并操作,有些细节还是要注意的。这样的话写成struct是最方便的,于是把代码又重构了一遍……其实也就是搜索替换一下就可以了。
#include<bits/stdc++.h>
#define mid (l+r)/2
using namespace std;
const int M=1e5+20;
int a[M];
struct Seg{
int lf,rt,lm,rm,mm,col,len;
Seg(int a=0,int b=0,int c=0,int d=0,int e=0,int f=0,int g=0):lf(a),rt(b),lm(c),rm(d),mm(e),col(f),len(g){}
}v[4*M];
inline Seg merge(Seg lef,Seg rit){
Seg ans;
ans.lf=lef.lf,ans.rt=rit.rt;
ans.len=lef.len+rit.len;
if (lef.col==1&&lef.rt<rit.lf)
ans.lm=lef.lm+rit.lm;
else
ans.lm=lef.lm;
if (rit.col==1&&lef.rt<rit.lf)
ans.rm=rit.rm+lef.rm;
else
ans.rm=rit.rm;
ans.mm=max(lef.mm,rit.mm);
if (lef.rt<rit.lf)
ans.mm=max(ans.mm,lef.rm+rit.lm);
if (ans.mm==0)
ans.col=0;
else if (ans.mm==ans.len)
ans.col=1;
else
ans.col=-1;
return ans;
}
void build(int id,int l,int r){
if (l==r){
v[id].lf=v[id].rt=a[l],
v[id].col=v[id].lm=v[id].rm=v[id].mm=v[id].len=1;
return;
}
build(id*2,l,mid);
build(id*2+1,mid+1,r);
v[id]=merge(v[id*2],v[id*2+1]);
}
void operate(int id,int l,int r,int pos,int x){
if (l==r){
v[id].lf=v[id].rt=x,
v[id].lm=v[id].rm=v[id].mm=v[id].col=1;
return;
}
if(pos<=mid)
operate(id*2,l,mid,pos,x);
else
operate(id*2+1,mid+1,r,pos,x);
v[id]=merge(v[id*2],v[id*2+1]);
}
Seg query(int id,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)
return v[id];
Seg lef,rit;
if(ql<=mid)
lef=query(id*2,l,mid,ql,qr);
if (mid<qr)
rit=query(id*2+1,mid+1,r,ql,qr);
if (lef.mm==0)
return rit;
if (rit.mm==0)
return lef;
return merge(lef,rit);
}
int main(){
int T;
scanf("%d",&T);
for(int z=1;z<=T;++z){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;++i){
char s[2];
int a,b;
scanf("%s%d%d",s,&a,&b);
if (s[0]=='Q')
printf("%d
",query(1,1,n,a+1,b+1).mm);
else
operate(1,1,n,a+1,b);
}
}
return 0;
}
CDQ
- HDU1541:二维偏序。
思路:和之前一样。这里求的是(a_2leq a)且(b_2leq b)的数量,对每个数量输出满足条件的个数。排序必须要第一维为第一关键字,第二维为第二关键字!不然后面数顺序对会出错!再用CDQ求顺序对个数。对于第i个数,以他为结尾的顺序对+逆序对=i-1,所以可以直接求逆序对个数,记录每个数对应逆序对的个数,再剪一下即可。这里用了结构体,所以一定是先修改答案,再存入ca数组!!!
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r)/2
const int M=1e5+20;
int res[M];
struct Star{
int x,y,num,ans;
Star(int a=0,int b=0,int c=0,int d=0):x(a),y(b),num(c),ans(d){}
}star[M],ca[M];
bool cmp(const Star &a,const Star &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
void CDQ(int l,int r){
if (l==r)
return;
CDQ(l,mid),CDQ(mid+1,r);
int i=l,j=mid+1,k=l;
while (i<=mid&&j<=r)
if (star[i].y<=star[j].y)
ca[k++]=star[i++];
else
star[j].ans+=mid-i+1,ca[k++]=star[j],++j;
while (i<=mid)
ca[k++]=star[i++];
while (j<=r)
ca[k++]=star[j++];
for (int i=l;i<=r;++i)
star[i]=ca[i];
}
int main(){
int n;
while(~scanf("%d",&n)){
for (int i=1;i<=n;++i)
scanf("%d%d",&star[i].x,&star[i].y),star[i].ans=0,res[i-1]=0;
sort(star+1,star+n+1,cmp);
for(int i=1;i<=n;++i)
star[i].num=i;
CDQ(1,n);
for(int i=1;i<=n;++i)
++res[star[i].num-1-star[i].ans];
for(int i=0;i<=n-1;++i)
printf("%d
",res[i]);
}
return 0;
}