线段树题集
hdu1199-Color the Ball(区间覆盖)
/* 题意:有无限个球排成一行,刚开始是黑色,然后他可以给一段区间染成 黑色或白色,最后要求找出最长连续白球序列,如果有多解,输出最左边 的,不存在输出Oh, my god 解析:因为是无限大,所以要离散化,我为了方便,将坐标扩大了3倍 每次插入区间的时候插入[L,R+1],插入完之后整个压下去,记录每个位置 是白色还是黑色,然后更新答案即可,具体细节见代码。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; const int maxn=2005; int N,Size; struct node { int L,R; char C[2]; }Nod[maxn]; vector<int> ve; struct Tree { int le,ri,lazy; }tree[3*4*2*maxn]; int mark[3*2*maxn]; void GetPos() { sort(ve.begin(),ve.end()); ve.erase(unique(ve.begin(),ve.end()),ve.end()); for(int i=0;i<N;i++) //离散化 { node& t=Nod[i]; t.L=lower_bound(ve.begin(),ve.end(),t.L)-ve.begin(); t.L*=3; //扩大3倍 t.R=lower_bound(ve.begin(),ve.end(),t.R)-ve.begin(); t.R*=3; } } void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.lazy=-1; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushdown(int id) { if(tree[id].lazy!=-1) { tree[id*2].lazy=tree[id*2+1].lazy=tree[id].lazy; tree[id].lazy=-1; } } void update(int id,int x,int y,int c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y){ e.lazy=c; return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); return; } void query(int id) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(le==ri) { mark[le]=abs(e.lazy); return; } pushdown(id); query(id*2); query(id*2+1); return; } int GetAns(int a,int b,int& ra,int& rb) { ra=ve[a/3],rb=ve[(b+1)/3]; if(a%3!=0) ra++; //不为0说明左端点的这个位置被占了,要加1 if(b%3!=1) rb--; //不为1说明右端点的这个位置被占了,要减1 return rb-ra+1; } void solve() { Size=ve.size()-1; build_tree(1,0,3*Size+1); //建树 for(int i=0;i<N;i++) { node& t=Nod[i]; if(t.C[0]=='w') update(1,t.L,t.R+1,0); //0代表白色, //R+1是用于后面判断右端点是否被覆盖 else update(1,t.L,t.R+1,1); //1代表黑色 } query(1); //整个压下去 int ret=0; int pre=-1; vector<pair<int,int> > V; V.clear(); for(int i=0;i<=3*Size+1;i++) { if(mark[i]) //被标记为黑色 { if(pre!=-1) V.push_back(make_pair(pre,i-1)); //找到一段 pre=-1; continue; } if(pre==-1) pre=i;//当前是白色起点位置,之前是黑色 } if(pre!=-1) V.push_back(make_pair(pre,3*Size+1)); //最后还有一段 int ansa=-1,ansb=-1; for(int i=0;i<V.size();i++) { int a=V[i].first,b=V[i].second; int ra,rb; int tt=GetAns(a,b,ra,rb); if(ret<tt){ ret=tt; ansa=ra,ansb=rb; } //找答案 } if(ansa==-1) printf("Oh, my god\n"); //无解 else printf("%d %d\n",ansa,ansb); //打印两个位置 } int main() { while(scanf("%d",&N)!=EOF) { ve.clear(); for(int i=0;i<N;i++) { scanf("%d%d%s",&Nod[i].L,&Nod[i].R,Nod[i].C); if(Nod[i].L>Nod[i].R) swap(Nod[i].L,Nod[i].R);//以防万一才写的 ve.push_back(Nod[i].L); ve.push_back(Nod[i].R); } GetPos(); solve(); } return 0; }
hdu1255- 覆盖的面积(扫描线+矩形多重覆盖)
/* 题意:计算至少覆盖两次的区域的面积 解析:裸的扫描线,但是是超过2次覆盖,这里再增加一个 ss这个变量,代表两次及以上覆盖的长度,我也是看别人 博客做的,固定的模式。。。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; const int maxn=2005; struct node { double L,R,H; int c; node(double L=0,double R=0,double H=0,int c=1) :L(L),R(R),H(H),c(c){} bool operator < (const node& t) const { return H<t.H; } }Nod[maxn]; int N,num; double A[maxn]; struct Tree { int le,ri,d; double s,ss; }tree[8*maxn]; void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.d=0; e.s=0,e.ss=0; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushup(int id) { Tree& fa=tree[id]; Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; int le=fa.le,ri=fa.ri; if(fa.d) fa.s=A[ri+1]-A[le]; else if(le==ri) fa.s=0; else fa.s=lson.s+rson.s; if(fa.d>1) fa.ss=A[ri+1]-A[le]; else if(le==ri) fa.ss=0; else if(fa.d==1) fa.ss=lson.s+rson.s; else fa.ss=lson.ss+rson.ss; } void update(int id,int x,int y,int c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x==le&&ri==y) { e.d+=c; pushup(id); return; } int mid=(le+ri)/2; if(y<=mid) update(id*2,x,y,c); else if(x>mid) update(id*2+1,x,y,c); else { update(id*2,x,mid,c); update(id*2+1,mid+1,y,c); } pushup(id); return; } double solve() { sort(Nod+1,Nod+num+1); sort(A+1,A+num+1); int k=1; for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; //去重 build_tree(1,1,k); double ret=0; for(int i=1;i<num;i++) { node& t=Nod[i]; int x=lower_bound(A+1,A+k+1,t.L)-A; //下标 int y=lower_bound(A+1,A+k+1,t.R)-A-1; update(1,x,y,t.c); //更新 ret+=tree[1].ss*(Nod[i+1].H-Nod[i].H); } return ret; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&N); num=0; double x1,y1,x2,y2; for(int i=1;i<=N;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); //输入坐标 Nod[++num]=node(x1,x2,y1,1); //增加下边 A[num]=x1; //为了离散化所用 Nod[++num]=node(x1,x2,y2,-1); //增加上边 A[num]=x2; } printf("%.2lf\n",solve()); } return 0; }
hdu3074-Multiply game(成段更新取乘积)
/* 题意:计算一段区间的乘积模上1000000007 解析:裸的线段树成段更新,计算的时候乘积取模就可以了 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] const int maxn=50005; const LL mod=1e9+7; struct Tree { int le,ri; LL sum; }tree[4*maxn]; void pushup(int id){ fa.sum=(lson.sum*rson.sum)%mod; } void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri; if(le==ri) { scanf("%I64d",&e.sum); return; } int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); pushup(id); return; } void update(int id,int k,LL v) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(le==ri) { e.sum=v%mod; return; } int mid=(le+ri)/2; if(k<=mid) update(id*2,k,v); else update(id*2+1,k,v); pushup(id); return; } LL query(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.sum; LL ret=1; int mid=(le+ri)/2; if(x<=mid) ret*=query(id*2,x,y); if(y>mid) ret*=query(id*2+1,x,y); return ret%mod; } int main() { int T; scanf("%d",&T); while(T--) { int N; scanf("%d",&N); build_tree(1,1,N); int M; scanf("%d",&M); int op,x,y; for(int k=1;k<=M;k++) { scanf("%d%d%d",&op,&x,&y); if(op==0) printf("%I64d\n",query(1,x,y)); else update(1,x,(LL)y); } } return 0; }
hdu3255-Farming(扫描线)
/* 题意:有N种不同的蔬菜,每种蔬菜有一个价格,给出M 块矩形田地以及这块田地上种植的是哪种蔬菜。覆盖的 地方价格最高的那种蔬菜会生存下去。问最多可以获得 多大的收益。 解析:对价格排个序,然后开始枚举price[i],把种植价格 大于等于price[i]的田地加进去进行扫描线,答案加上面 积乘上price[i]-price[i-1]的差值。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] #define e tree[id] const int maxn=60005; struct Po { int x1,y1,x2,y2,val; Po(int x1=0,int y1=0,int x2=0,int y2=0,int val=0) :x1(x1),y1(y1),x2(x2),y2(y2),val(val){} }P[maxn]; struct node { int L,R,H,s; node(int L=0,int R=0,int H=0,int s=1) :L(L),R(R),H(H),s(s){} bool operator < (const node& t) const { return H<t.H; } }Nod[maxn]; struct Tree { int le,ri,c,sum; }tree[4*maxn]; int N,M,num,price[4],A[maxn]; void AddLine(Po& t) { Nod[++num]=node(t.x1,t.x2,t.y1,1); A[num]=t.x1; Nod[++num]=node(t.x1,t.x2,t.y2,-1); A[num]=t.x2; } void build_tree(int id,int le,int ri) { e.le=le,e.ri=ri,e.c=e.sum=0; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushup(int id) { int le=fa.le,ri=fa.ri; if(fa.c) fa.sum=A[ri+1]-A[le]; else if(le==ri) fa.sum=0; else fa.sum=lson.sum+rson.sum; } void update(int id,int x,int y,int c) { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.c+=c; pushup(id); return; } int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); pushup(id); return; } LL Get() //扫描线 { sort(Nod+1,Nod+num+1); sort(A+1,A+num+1); int k=1; for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; //去重 build_tree(1,1,k); //建树 LL ret=0; for(int i=1;i<num;i++) //模板 { node& t=Nod[i]; int x=lower_bound(A+1,A+k+1,t.L)-A; int y=lower_bound(A+1,A+k+1,t.R)-A-1; if(x>y) continue; update(1,x,y,t.s); ret+=(LL)tree[1].sum*(Nod[i+1].H-Nod[i].H); } return ret; } LL solve() { price[0]=0; sort(price+1,price+M+1); LL ret=0; for(int i=1;i<=M;i++) //依次加起来 { num=0; for(int j=1;j<=N;j++) if(P[j].val>=price[i]) AddLine(P[j]); //增加这条边 ret+=Get()*(price[i]-price[i-1]); //把差值加上 } return ret; } int main() { int T,Case=0; scanf("%d",&T); while(T--) { scanf("%d%d",&N,&M); for(int i=1;i<=M;i++) scanf("%d",&price[i]); int x1,y1,x2,y2,type; for(int i=1;i<=N;i++) { scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&type); P[i]=Po(x1,y1,x2,y2,price[type]); } printf("Case %d: %I64d\n",++Case,solve()); } return 0; }
hdu3642-Get The Treasury(扫描线+三重覆盖)
/* 题意:求覆盖至少三次的体积 解析:离散化高度,扫描线求面积,覆盖三次 增加3个变量s,ss,sss,分别记录至少覆盖一次,两次,三次 的区间长度 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef long long LL; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] #define e tree[id] const int maxn=2005; int N,num; struct Point { int x1,y1,z1,x2,y2,z2; Point(int x1=0,int y1=0,int z1=0,int x2=0,int y2=0,int z2=0) :x1(x1),y1(y1),z1(z1),x2(x2),y2(y2),z2(z2){} }P[maxn]; struct node { int L,R,H,s; node(int L=0,int R=0,int H=0,int s=0) :L(L),R(R),H(H),s(s){} bool operator < (const node& t) const { return H<t.H; } }Nod[maxn]; struct Tree { int le,ri,c; int s,ss,sss; }tree[4*maxn]; int A[maxn]; void AddLine(Point& p) { Nod[++num]=node(p.x1,p.x2,p.y1,1); A[num]=p.x1; Nod[++num]=node(p.x1,p.x2,p.y2,-1); A[num]=p.x2; } void build_tree(int id,int le,int ri) { e.le=le,e.ri=ri,e.s=e.ss=e.sss=0,e.c=0; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushup(int id) //这个地方是重点 { int le=fa.le,ri=fa.ri; if(fa.c) fa.s=A[ri+1]-A[le]; else if(le==ri) fa.s=0; else fa.s=lson.s+rson.s; if(fa.c>=2) fa.ss=A[ri+1]-A[le]; else if(le==ri) fa.ss=0; else if(fa.c==1) fa.ss=lson.s+rson.s; else fa.ss=lson.ss+rson.ss; if(fa.c>=3) fa.sss=A[ri+1]-A[le]; else if(le==ri) fa.sss=0; else if(fa.c==2) fa.sss=lson.s+rson.s; else if(fa.c==1) fa.sss=lson.ss+rson.ss; else fa.sss=lson.sss+rson.sss; } void update(int id,int x,int y,int c) { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.c+=c; pushup(id); return; } int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); pushup(id); return; } LL Get() //扫描线模板 { if(num<6) return 0; sort(Nod+1,Nod+num+1); sort(A+1,A+num+1); int k=1; for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; build_tree(1,1,k-1); int x,y; LL ret=0; for(int i=1;i<num;i++) { node& t=Nod[i]; x=lower_bound(A+1,A+k+1,t.L)-A; y=lower_bound(A+1,A+k+1,t.R)-A-1; update(1,x,y,t.s); ret+=(LL)tree[1].sss*(Nod[i+1].H-Nod[i].H); } return ret; } int B[maxn]; LL solve() { LL ret=0; sort(B+1,B+num+1); int k=1; for(int i=2;i<=num;i++) if(B[i]!=B[k]) B[++k]=B[i]; //离散化高度 for(int i=2;i<=k;i++) //枚举 { num=0; for(int j=1;j<=N;j++) { Point& p=P[j]; if(p.z1<B[i]&&p.z2>=B[i]) AddLine(p); //把边加进去 } LL add=Get(); ret+=add*((LL)B[i]-B[i-1]); //加上这一层的体积 } return ret; } int main() { int T,Case=0; scanf("%d",&T); while(T--) { scanf("%d",&N); int x1,x2,y1,y2,z1,z2; num=0; for(int i=1;i<=N;i++) { scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); P[i]=Point(x1,y1,z1,x2,y2,z2); //增加一个长方体 B[++num]=z1; B[++num]=z2; } LL ans=solve(); printf("Case %d: %lld\n",++Case,ans); } return 0; }
hdu3911-Black And White(线段树01翻转)
/* 题意:可以将一段区间黑变成白,白变成黑,查询时问最长连续黑色的 长度是多少 解析:线段树区间合并,设置wll(白色左边连续的长度),wrl(白色右边连续的长度) wml(白色最长的连续长度),bll(黑色左边连续的长度),brl(黑色右边连续的长度) bml(黑色最长的连续长度)。没次pushup都要更新这些值,具体细节见代码。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] const int maxn=100005; struct Tree { int le,ri,len,c,d; int wll,wrl,wml; int bll,brl,bml; void init() { bll=brl=bml=len*c; wll=wrl=wml=len*(c^1); } void f() { swap(bll,wll); swap(brl,wrl); swap(bml,wml); //黑白交换 } }tree[4*maxn]; int N,M; void pushup(int id) { fa.bll=lson.bll; if(fa.bll==lson.len) fa.bll+=rson.bll; //延伸到右边去 fa.brl=rson.brl; if(fa.brl==rson.len) fa.brl+=lson.brl; //延伸到左边去 fa.bml=max(lson.bml,rson.bml); //更新最大值 fa.bml=max(fa.bml,max(fa.bll,fa.brl)); fa.bml=max(fa.bml,lson.brl+rson.bll); fa.wll=lson.wll; //同理 if(fa.wll==lson.len) fa.wll+=rson.wll; fa.wrl=rson.wrl; if(fa.wrl==rson.len) fa.wrl+=lson.wrl; fa.wml=max(lson.wml,rson.wml); fa.wml=max(fa.wml,max(fa.wll,fa.wrl)); fa.wml=max(fa.wml,lson.wrl+rson.wll); } void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.len=ri-le+1,e.d=0; if(le==ri) { scanf("%d",&e.c); e.init(); return; } int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); pushup(id); } void pushdown(int id) { if(fa.d) { lson.d^=1; rson.d^=1; lson.f(),rson.f(); fa.d=0; } } void update(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.d^=1; //异或操作 e.f(); return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y); if(y>mid) update(id*2+1,x,y); pushup(id); return; } int query(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.bml; pushdown(id); int mid=(le+ri)/2; int ret=0; if(x<=mid) ret=max(ret,query(id*2,x,y)); //查询左边 if(y>mid) ret=max(ret,query(id*2+1,x,y)); //右边 if(x<=mid&&y>mid) ret=max(ret,min(mid-x+1,lson.brl)+min(y-mid,rson.bll));//中间合并的一段 pushup(id); return ret; } int main() { while(scanf("%d",&N)!=EOF) { build_tree(1,1,N); scanf("%d",&M); int op,x,y; for(int k=1;k<=M;k++) { scanf("%d%d%d",&op,&x,&y); if(op==1) update(1,x,y); //更新 else printf("%d\n",query(1,x,y)); //查询 } } return 0; }
poj1177-Picture(扫描线求周长)
/* 题意:求周长 解析:x轴方向来一遍扫描线,y轴方向来一遍 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e8+7; const double eps=1e-7; typedef __int64 LL; const int maxn=20005; int N,num; struct node { int L,R,H,s; node(int L=0,int R=0,int H=0,int s=1) :L(L),R(R),H(H),s(s){} bool operator < (const node& t) const { return H<t.H; } }Row[maxn],Col[maxn]; int RV[maxn],CV[maxn]; struct Tree { int le,ri,lazy,d; }tree[4*maxn]; int ans; void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.d=-1; if(le==ri) { e.d=0; return; } int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } int GetAns(int a,int b,int type) { if(type==0) return RV[b]-RV[a]; else return CV[b]-CV[a]; } void pushdown(int id) { Tree& fa=tree[id]; Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; if(fa.d!=-1) { lson.d=rson.d=fa.d; fa.d=-1; } } void pushup(int id) { Tree& fa=tree[id]; Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; if(lson.d==-1||rson.d==-1) fa.d=-1; else if(lson.d!=rson.d) fa.d=-1; else fa.d=lson.d; } void update(int id,int x,int y,int c,int type) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y&&e.d!=-1) { if(e.d==0&&c==1) ans+=GetAns(le,ri+1,type); else if(e.d==1&&c==-1) ans+=GetAns(le,ri+1,type); e.d+=c; return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c,type); if(y>mid) update(id*2+1,x,y,c,type); pushup(id); return; } int Get(node A[],int B[],int type) //type是类型,指的是行或者列 { sort(A+1,A+num+1); sort(B+1,B+num+1); int k=1; for(int i=2;i<=num;i++) if(B[i]!=B[k]) B[++k]=B[i]; build_tree(1,1,k); int ret=0; for(int i=1;i<=num;i++) { node& e=A[i]; int x=lower_bound(B+1,B+k+1,e.L)-B; int y=lower_bound(B+1,B+k+1,e.R)-B-1; ans=0; if(x>y) continue; update(1,x,y,e.s,type); ret+=ans; } return ret; } int solve() { int ret=0; ret+=Get(Row,RV,0); //行方向 ret+=Get(Col,CV,1); //列方向 return ret; } int main() { while(scanf("%d",&N)!=EOF) { if(N==0) { printf("0\n"); continue; } num=0; for(int i=1;i<=N;i++) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); ++num; Row[num]=node(x1,x2,y1,1); //行 Col[num]=node(y1,y2,x1,1); //列 RV[num]=x1; CV[num]=y1; ++num; Row[num]=node(x1,x2,y2,-1); Col[num]=node(y1,y2,x2,-1); RV[num]=x2; CV[num]=y2; } printf("%d\n",solve()); } return 0; }
poj2777-Count Color(线段树+状态压缩)
/* 题意:给一段区间染色,颜色最多30种,查询一段区间有多少种颜色 解析:状态压缩,增加S变量,如果哪种颜色被染了,则对应的二进制位为1 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; const int maxn=100005; typedef __int64 LL; struct Tree { int le,ri,lazy; LL S; }tree[4*maxn]; int L,T,O; void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.S=2,e.lazy=-1; //S=2代表染了1这种颜色 if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushdown(int id) { if(tree[id].lazy!=-1) //延迟更新 { tree[id*2].lazy=tree[id*2+1].lazy=tree[id].lazy; tree[id*2].S=tree[id*2+1].S=tree[id].S; tree[id].lazy=-1; } } void pushup(int id) { tree[id].S=tree[id*2].S | tree[id*2+1].S; //或运算 } void update(int id,int x,int y,int c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y){ e.lazy=c; e.S=(LL)1<<c; return; } //染c色 pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); pushup(id); return; } LL query(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.S; pushdown(id); int mid=(le+ri)/2; LL ret=0; if(x<=mid) ret|=query(id*2,x,y); if(y>mid) ret|=query(id*2+1,x,y); pushup(id); return ret; } int main() { scanf("%d%d%d",&L,&T,&O); char op[2]; int x,y,c; build_tree(1,1,L); while(O--) { scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d",&x,&y,&c); update(1,x,y,c); } else { scanf("%d%d",&x,&y); if(x>y) swap(x,y); LL S=query(1,x,y); int ans=0; while(S) //计算有多少种颜色 { if(S&1) ans++; S>>=1; } printf("%d\n",ans); } } return 0; }
poj2828-Buy Tickets(线段树查询空位)
/* 题意:排队,但是可以插队,一个人来了可以插到第i个人之后 0代表柜台,问最后的队伍顺序。 解析:一开始建树时每一段都是空的,所以大小就是区间长度, 从后面往前面插入,如果左边位置足够,则插到左边,否则右边 找到插入位置后,空位减1 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; const int maxn=200005; int N,ans[maxn]; int pos[maxn],val[maxn]; struct Tree { int le,ri; int num; }tree[4*maxn]; void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri; e.num=ri-le+1; //一开始都是空的 if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void update(int id,int p,int v) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(le==ri){ e.num--; ans[le]=v; return; } //插入进去,空间减1 Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; if(lson.num>=p) update(id*2,p,v); //左边足够,则插到左边 else update(id*2+1,p-lson.num,v); //否则右边 e.num=lson.num+rson.num; //更新 return; } int main() { while(scanf("%d",&N)!=EOF) { for(int i=0;i<N;i++) scanf("%d%d",&pos[i],&val[i]); //输入 build_tree(1,0,N-1); //建树 for(int i=N-1;i>=0;i--) update(1,pos[i]+1,val[i]); //插入到第Pos[i]+1的位置 for(int i=0;i<N;i++) //输出 { if(i) printf(" "); printf("%d",ans[i]); } printf("\n"); } return 0; }
poj3225-Help with Intervals(线段树+区间异或)
/* 题意:给出了几种集合运算,每次操作对一段区间进行其中的一种运算 输出最后被覆盖的区间段,要注意开区间与闭区间 解析:注意一下每种运算如何修改区间的值,在线段树里再增加两个变量 d(整个区间的值),c(是否需要异或),具体细节见代码。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] #define e tree[id] const int maxn=140000; struct Tree { int le,ri,d,c; //d是区间的值,c代表是否需要异或 void UpXor() { if(d!=-1) d^=1; //是整个连续相同的 else c^=1; //懒惰标记异或 } }tree[4*maxn]; void build_tree(int id,int le,int ri) { e.le=le,e.ri=ri,e.d=0,e.c=0; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } inline void pushdown(int id) { if(fa.d!=-1) { lson.d=rson.d=fa.d; lson.c=rson.c=0; fa.d=-1; } if(fa.c) { lson.UpXor(); rson.UpXor(); fa.c=0; } } inline void Link(int id,char op) { if(op=='U') fa.d=1,fa.c=0; //并集 else if(op=='D') fa.d=0,fa.c=0; //差集S-T else if(op=='C'||op=='S') fa.UpXor(); //异或 } void update(int id,int x,int y,char op) { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { Link(id,op); return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,op); //左边可更新 else if(op=='I'||op=='C') lson.d=lson.c=0; //如果是交集或者是差集T-S,左边都要置为0 if(y>mid) update(id*2+1,x,y,op); //右边同理 else if(op=='I'||op=='C') rson.d=rson.c=0; return; } int mark[maxn]; //标记某位置是否被占 vector<pair<int,int> > ve; void query(int id) { if(e.le==e.ri) { mark[e.le]=e.d; return; } //一直压到叶子节点 pushdown(id); query(id*2); query(id*2+1); return; } int main() { char op,a,b; int x,y; build_tree(1,0,131070); //扩大了2倍 while(scanf("%c %c%d,%d%c",&op,&a,&x,&y,&b)!=EOF) { getchar(); x*=2; y*=2; //乘2 if(a=='(') x++; //不是实区间加1 if(b==')') y--; if(x>y) //区间为空 { if(op=='I'||op=='C') tree[1].c=tree[1].d=0; continue; } update(1,x,y,op); //更新 } memset(mark,0,sizeof(mark)); query(1); //整个压下去 ve.clear(); int pre=-1; for(int i=0;i<=131075;i++) { if(mark[i]) { if(pre!=-1) continue; pre=i; } else { if(pre==-1) continue; ve.push_back(make_pair(pre,i-1)); //找区间段 pre=-1; } } if(ve.size()==0) printf("empty set\n"); //为空 else { int kase=0; for(int i=0;i<ve.size();i++) //输出很恶心 { int L=ve[i].first; int R=ve[i].second; if(kase++) printf(" "); if(L%2) printf("("); else printf("["); printf("%d,%d",L/2,(R+1)/2); if(R%2) printf(")"); else printf("]"); } printf("\n"); } return 0; }
poj3277-City Horizon(扫描线)
/* 题意:给出N个矩形,都在同一水平线上,求面积并 解析:裸的扫描线 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; const int maxn=80005; int N,num,A[maxn]; struct node { int L,R,H,s; node(int L=0,int R=0,int H=0,int s=0) :L(L),R(R),H(H),s(s){} bool operator < (const node& t) const { return H<t.H; } }Nod[maxn]; struct Tree { int le,ri,lazy; int sum; }tree[4*maxn]; void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.lazy=0,e.sum=0; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushup(int id) { Tree& fa=tree[id]; Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; if(fa.lazy) fa.sum=A[fa.ri+1]-A[fa.le]; else if(fa.le==fa.ri) fa.sum=0; else fa.sum=lson.sum+rson.sum; } void update(int id,int x,int y,int c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.lazy+=c; pushup(id); return; } int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); pushup(id); return; } LL solve() { LL ret=0; sort(Nod+1,Nod+num+1); sort(A+1,A+num+1); int k=1; for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; build_tree(1,1,k); for(int i=1;i<num;i++) { node& t=Nod[i]; int x=lower_bound(A+1,A+k+1,t.L)-A; int y=lower_bound(A+1,A+k+1,t.R)-A-1; update(1,x,y,t.s); ret+=(LL)tree[1].sum*((LL)Nod[i+1].H-Nod[i].H); } return ret; } int main() { while(scanf("%d",&N)!=EOF) { num=0; int a,b,h; for(int i=1;i<=N;i++) { scanf("%d%d%d",&a,&b,&h); Nod[++num]=node(a,b,0,1); A[num]=a; Nod[++num]=node(a,b,h,-1); A[num]=b; } LL ans=solve(); printf("%I64d\n",ans); } return 0; }
poj3368-Frequent values(线段树区间合并)
/* 题意:给出一组非递减的数,每次查询一段区间内出现次数最多的数的个数 解析:因为是非递减的,而且也不能更改,所以相同的数是连在一起的, 考虑用线段树区间合并记录连续的最大长度。具体细节见代码。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; typedef __int64 LL; const int maxn=100005; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] int N,Q; struct Tree { int le,ri,len; int ll,rl,ml; //左边连续长度,右边连续长度,最大连续长度 int lv,rv; //左端点值,右端点值 }tree[4*maxn]; void pushup(int id) { fa.ll=lson.ll; if(fa.ll==lson.len&&lson.rv==rson.lv) fa.ll+=rson.ll; //延伸到右边去 fa.rl=rson.rl; if(fa.rl==rson.len&&lson.rv==rson.lv) fa.rl+=lson.rl; //延伸到左边去 fa.ml=max(lson.ml,rson.ml); if(lson.rv==rson.lv) fa.ml=max(fa.ml,lson.rl+rson.ll); //取最大值 fa.lv=lson.lv; //左右端点的值 fa.rv=rson.rv; } void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le, e.ri=ri, e.len=ri-le+1; if(le==ri) { scanf("%d",&e.lv); e.rv=e.lv; e.ll=e.rl=e.ml=1; //叶子节点为1 return; } int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); pushup(id); return; } int query(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.ml; int mid=(le+ri)/2; int ret=0; if(x<=mid) ret=max(ret,query(id*2,x,y)); //左边 if(y>mid) ret=max(ret,query(id*2+1,x,y)); //右边 if(x<=mid&&y>mid) { if(lson.rv==rson.lv) ret=max(ret,min(lson.rl,mid-x+1)+min(rson.ll,y-mid)); //中间 } return ret; } int main() { while(true) { scanf("%d",&N); if(!N) break; scanf("%d",&Q); build_tree(1,1,N); int x,y; for(int i=1;i<=Q;i++) { scanf("%d%d",&x,&y); printf("%d\n",query(1,x,y)); } } return 0; }
zoj1610-Count the Colors(线段树区间覆盖)
/* 题意:给区间染色,最后求每种可见的颜色有多少段 解析:区间覆盖问题,最后整个压下去,统计一下个数即可。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; const int INF=1e9+7; const double eps=1e-7; const int maxn=8005; struct Tree { int le,ri,lazy; }tree[4*maxn]; int N; int color[maxn],mark[maxn]; //mark标记颜色,color记录个数 void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.lazy=-1; if(le==ri) return; int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); return; } void pushdown(int id) { Tree& fa=tree[id]; Tree& lson=tree[id*2]; Tree& rson=tree[id*2+1]; if(fa.lazy!=-1) { lson.lazy=rson.lazy=fa.lazy; fa.lazy=-1; } } void update(int id,int x,int y,int c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.lazy=c; if(le==ri) mark[le]=c; //叶子节点 return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); return; } void query(int id) { Tree& e=tree[id]; int le=e.le,ri=e.ri,lazy=e.lazy; if(le==ri) { mark[le]=lazy; //一直到叶子节点 return; } pushdown(id); query(id*2); query(id*2+1); return; } int main() { while(scanf("%d",&N)!=EOF) { build_tree(1,1,8000); int x,y,c; memset(mark,-1,sizeof(mark)); for(int i=1;i<=N;i++) { scanf("%d%d%d",&x,&y,&c); update(1,x+1,y,c); } query(1); memset(color,0,sizeof(color)); for(int i=1;i<=8000;i++) //统计个数 if(mark[i]!=mark[i-1]) color[mark[i]]++; for(int i=0;i<=8000;i++) //不为0可见 if(color[i]) printf("%d %d\n",i,color[i]); printf("\n"); } return 0; }
zoj2706-Thermal Death of the Universe(线段树成段更新)
/* 题意:更新一段区间,把这段区间的数全部置为其平均数 如果这段区间的和小于等于总和则向上取整,否则向下取整 解析:线段树成段更新,注意一下题目的要求即可。 */ #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<sstream> #include<utility> #include<iterator> using namespace std; typedef long long LL; const LL INF=1e15+7; const double eps=1e-7; #define fa tree[id] #define lson tree[id*2] #define rson tree[id*2+1] const int maxn=30005; struct Tree { int le,ri; LL sum,d; void init(){ sum=d*(ri-le+1); } }tree[4*maxn]; int N,M; LL mark[maxn]; void pushup(int id) { fa.sum=lson.sum+rson.sum; } void build_tree(int id,int le,int ri) { Tree& e=tree[id]; e.le=le,e.ri=ri,e.d=-INF; if(le==ri) { scanf("%lld",&e.sum); e.d=e.sum; return; } int mid=(le+ri)/2; build_tree(id*2,le,mid); build_tree(id*2+1,mid+1,ri); pushup(id); return; } void pushdown(int id) { if(fa.d!=-INF) { lson.d=rson.d=fa.d; lson.init(); rson.init(); fa.d=-INF; } } void update(int id,int x,int y,LL c) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) { e.d=c; e.init(); return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) update(id*2,x,y,c); if(y>mid) update(id*2+1,x,y,c); pushup(id); return; } LL query(int id,int x,int y) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.sum; pushdown(id); int mid=(le+ri)/2; LL ret=0; if(x<=mid) ret+=query(id*2,x,y); if(y>mid) ret+=query(id*2+1,x,y); pushup(id); return ret; } void GetMark(int id) { Tree& e=tree[id]; int le=e.le,ri=e.ri; if(le==ri){ mark[le]=e.sum; return; } pushdown(id); GetMark(id*2); GetMark(id*2+1); return; } int main() { while(scanf("%d%d",&N,&M)!=EOF) { build_tree(1,1,N); LL org=tree[1].sum; int x,y; for(int k=1;k<=M;k++) { scanf("%d%d",&x,&y); LL S=query(1,x,y); LL L=y-x+1; if(tree[1].sum<=org) { if(S<0) update(1,x,y,-(-S/L)); else update(1,x,y,(S+L-1)/L); } else { if(S<0) update(1,x,y,-((-S+L-1)/L)); else update(1,x,y,S/L); } } GetMark(1); int kase=0; for(int i=1;i<=N;i++) { if(kase++) printf(" "); printf("%lld",mark[i]); } printf("\n\n"); } return 0; }