12.7日记
线段树
- POJ3667:区间修改+询问最靠左的长度为x的连续区间。
思路和上个题差不多,只不过这里是区间修改,所以只能用线段树了。这里注意如果是直接修改值的话,lazy标记的初始值必须是-1,因为可以改成0。出了点小错误,以后写代码还是要仔细。
#include
#include
#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=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\n",ca);
}
else{
int x,y;
scanf("%d%d",&x,&y);
operate(1,1,n,x,x+y-1,1);
}
}
}
return 0;
}
- HDU3308:单点修改+区间查询最长连续上升子序列
思路一样,只不过这里查询的时候,需要对两个区间进行合并操作,有些细节还是要注意的。这样的话写成struct是最方便的,于是把代码又重构了一遍……其实也就是搜索替换一下就可以了。
#include
#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
CDQ
- HDU1541:二维偏序。
思路:和之前一样。这里求的是\(a_2\leq a\)且\(b_2\leq b\)的数量,对每个数量输出满足条件的个数。排序必须要第一维为第一关键字,第二维为第二关键字!不然后面数顺序对会出错!再用CDQ求顺序对个数。对于第i个数,以他为结尾的顺序对+逆序对=i-1,所以可以直接求逆序对个数,记录每个数对应逆序对的个数,再剪一下即可。这里用了结构体,所以一定是先修改答案,再存入ca数组!!!
#include
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