线段树专题
线段树专题
先开个坑,这两天就刷线段树了!
----------------------------------
先来模板,用数组模拟树,注意开四倍空间。
【参考资料】:http://www.shuizilong.com/house/archives/%E3%80%90%E5%AE%8C%E5%85%A8%E7%89%88%E3%80%91%E7%BA%BF%E6%AE%B5%E6%A0%91%EF%BC%88%E8%BD%AC%E8%BD%BD%EF%BC%89/
以下为转载:
maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示
PushUP(int rt)是把当前结点的信息更新到父结点
PushDown(int rt)是把当前结点的信息更新给儿子结点
rt表示当前子树的根(root),也就是当前所在的结点
【模板1】单点更新,区间查询。
#define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int sum[maxn<<2]; int n; char op[10]; void PushUP(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r){ RI(sum[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); PushUP(rt); } void update(int p,int add,int l,int r,int rt) { if(l==r){ sum[rt]+=add; return; } int m=(l+r)>>1; if(p<=m) update(p,add,lson); else update(p,add,rson); PushUP(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return sum[rt]; int m=(l+r)>>1; int res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } int main() { DRI(T); int casen=1; while(T--){ RI(n); build(1,n,1); while(RS(op)&&op[0]!='E'){ DRII(a,b); if(op[0]=='Q') cout<<query(a,b,1,n,1)<<endl; else if(op[0]=='A') update(a,b,1,n,1); else if(op[0]=='S') update(a,-b,1,n,1); } } return 0; }
【模板2】区间更新,区间查询。(需设延迟标志tag)
#define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll sum[maxn<<2]; ll tag[maxn<<2]; int n,q; ll a,b,c; char op[10]; void PushUp(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void PushDown(int rt,int m) { if(tag[rt]){ tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt]; sum[rt<<1]+=tag[rt]*(m-(m>>1)); sum[rt<<1|1]+=tag[rt]*(m>>1); tag[rt]=0; } } void build(int l,int r,int rt) { tag[rt]=0; if(l==r){ scanf("%I64d",&sum[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(rt); } void update(int L,int R,ll key,int l,int r,int rt) { if(L<=l&&r<=R){ tag[rt]+=key; sum[rt]+=(r-l+1)*key; return; } PushDown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,key,lson); if(R>m) update(L,R,key,rson); PushUp(rt); } ll query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return sum[rt]; PushDown(rt,r-l+1); int m=(l+r)>>1; ll res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } int main() { freopen("in.txt","r",stdin); while(cin>>n>>q){ build(1,n,1); while(q--){ RS(op); if(op[0]=='C'){ scanf("%I64d%I64d%I64d",&a,&b,&c); update(a,b,c,1,n,1); } else{ scanf("%I64d%I64d",&a,&b); printf("%I64d\n",query(a,b,1,n,1)); } } } return 0; }
【模板3】离散化。
#define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 PII post[maxn]; int n; int p[maxn],cnt,m; int col[maxn<<2]; //map<int,int> id; bool vis[maxn<<2]; int ans; void push_down(int rt) { if(col[rt]){ col[rt<<1]=col[rt<<1|1]=col[rt]; col[rt]=0; } } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ col[rt]=c; return; } push_down(rt); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); } int query(int l,int r,int rt) { if(col[rt]){ if(!vis[col[rt]]){ vis[col[rt]]=1; return 1; } return 0; } if(l==r) return 0; int m=(l+r)>>1; return query(lson)+query(rson); } int main() { freopen("in.txt","r",stdin); DRI(T); while(T--){ RI(n); cnt=0; REP(i,1,n){ RII(post[i].fst,post[i].snd); p[++cnt]=post[i].fst; p[++cnt]=post[i].snd; } sort(p+1,p+cnt+1); m=1; REP(i,2,cnt){ if(p[i]!=p[i-1]) p[++m]=p[i]; } sort(p+1,p+m+1); cnt=m; REP(i,2,cnt){ if(p[i]-p[i-1]>1) p[++m]=p[i]-1; } sort(p+1,p+m+1); //id.clear(); //REP(i,1,m) id[p[i]]=i; MS0(col); REP(i,1,n){ //int L=id[post[i].fst]; //int R=id[post[i].snd]; int L=lower_bound(p+1,p+m+1,post[i].fst)-p; int R=lower_bound(p+1,p+m+1,post[i].snd)-p; update(L,R,i,1,m,1); } MS0(vis); cout<<query(1,m,1)<<endl; } return 0; }
【模板4】区间合并。
#define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int N,M; int msum[maxn],lsum[maxn],rsum[maxn]; int cover[maxn]; int op,a,b; void push_up(int rt,int m) { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(msum[rt<<1],msum[rt<<1|1])); } void push_down(int rt,int m) { if(cover[rt]!=-1){ cover[rt<<1]=cover[rt<<1|1]=cover[rt]; msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?0:(m-(m>>1)); msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cover[rt]?0:(m>>1); cover[rt]=-1; } } void build(int l,int r,int rt) { cover[rt]=-1; msum[rt]=lsum[rt]=rsum[rt]=r-l+1; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ cover[rt]=c; msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1; return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); push_up(rt,r-l+1); } int query(int w,int l,int r,int rt) { if(l==r) return l; push_down(rt,r-l+1); int m=(l+r)>>1; if(msum[rt<<1]>=w) return query(w,lson); else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1; return query(w,rson); } int main() { freopen("in.txt","r",stdin); while(~RII(N,M)){ build(1,N,1); while(M--){ RI(op); if(op==1){ RI(a); if(msum[1]<a) puts("0"); else{ int p=query(a,1,N,1); printf("%d\n",p); update(p,p+a-1,1,1,N,1); } } else RII(a,b),update(a,a+b-1,0,1,N,1); } } return 0; }
===================================================================================================================
A题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/A
敌兵布阵。 单点更新,区间求和。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int sum[maxn<<2]; int n; char op[10]; void PushUP(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r){ RI(sum[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); PushUP(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return sum[rt]; int m=(l+r)>>1; int res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } void update(int p,int add,int l,int r,int rt) { if(l==r){ sum[rt]+=add; return; } int m=(l+r)>>1; if(p<=m) update(p,add,lson); else update(p,add,rson); PushUP(rt); } int main() { freopen("in.txt","r",stdin); DRI(T); int casen=1; while(T--){ RI(n); build(1,n,1); printf("Case %d:\n",casen++); while(RS(op)&&op[0]!='E'){ DRII(a,b); if(op[0]=='A') update(a,b,1,n,1); else if(op[0]=='S') update(a,-b,1,n,1); else if(op[0]=='Q') cout<<query(a,b,1,n,1)<<endl; } } return 0; }
B题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/B
单点更新,区间最值。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int Max[maxn<<2]; int N,M; char op[10]; int A,B; void PushUP(int rt) { Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r){ RI(Max[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); PushUP(rt); } void update(int p,int key,int l,int r,int rt) { if(l==r){ Max[rt]=key; return; } int m=(l+r)>>1; if(p<=m) update(p,key,lson); else update(p,key,rson); PushUP(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return Max[rt]; int m=(l+r)>>1; int res=-INF; if(L<=m) res=max(res,query(L,R,lson)); if(R>m) res=max(res,query(L,R,rson)); return res; } int main() { freopen("in.txt","r",stdin); while(~RII(N,M)){ build(1,N,1); while(M--){ RS(op); RII(A,B); if(op[0]=='Q') printf("%d\n",query(A,B,1,N,1)); else update(A,B,1,N,1); } } return 0; }
7-29的B题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85027#problem/B
单点更新,区间(整个区间)第一个大于x的值的位置。查询的过程中顺便更新了。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=200100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll h,w,n; ll Max[maxn<<2]; void PushUP(int rt) { Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r){ Max[rt]=w; return; } int m=(l+r)>>1; build(lson); build(rson); PushUP(rt); } ll query(ll x,ll l,ll r,ll rt) { if(l==r){ Max[rt]-=x; return l; } int m=(l+r)>>1; ll res=0; if(Max[rt<<1]>=x) res=query(x,lson); else res=query(x,rson); PushUP(rt); return res; } int main() { freopen("in.txt","r",stdin); while(cin>>h>>w>>n){ h=min(h,n); build(1,h,1); REP(i,1,n){ ll x; scanf("%I64d",&x); if(Max[1]-x<0) puts("-1"); else printf("%I64d\n",query(x,1,h,1)); } } return 0; }
C题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/C
区间更新,区间求和。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=100100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll sum[maxn<<2],tag[maxn<<2]; ll n,q; ll a,b,c; char op[10]; void push_up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void push_down(int rt,int m) { if(tag[rt]){ tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt]; sum[rt<<1]+=tag[rt]*(m-(m>>1)); sum[rt<<1|1]+=tag[rt]*(m>>1); tag[rt]=0; } } void build(int l,int r,int rt) { tag[rt]=0; if(l==r){ scanf("%lld",&sum[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void update(int L,int R,ll x,int l,int r,int rt) { if(L<=l&&r<=R){ tag[rt]+=x; sum[rt]+=(r-l+1)*x; return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,x,lson); if(R>m) update(L,R,x,rson); push_up(rt); } ll query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return sum[rt]; push_down(rt,r-l+1); int m=(l+r)>>1; ll res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } int main() { freopen("in.txt","r",stdin); while(cin>>n>>q){ build(1,n,1); while(q--){ RS(op); if(op[0]=='C'){ scanf("%lld%lld%lld",&a,&b,&c); update(a,b,c,1,n,1); } else{ scanf("%lld%lld",&a,&b); printf("%lld\n",query(a,b,1,n,1)); } } } return 0; }
xdoj1013:
http://acm.xidian.edu.cn/problem.php?id=1013
区间更新,区间状态维护;区间求和,全区间的最终状态。
区间的维护通过区间的和sum来维护,当l==r时,sum[rt]即等于a[i]。全区间的最终状态最后直接按类似建树的过程一直搜下去即可,先左后右可以保证按顺序。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=100100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int n,m; ll sum[maxn<<2]; ll tag[maxn<<2]; int l,r,k; ll avg,ans; void push_up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void push_down(int rt,int m) { if(tag[rt]){ tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt]; sum[rt<<1]+=tag[rt]*(m-(m>>1)); sum[rt<<1|1]+=tag[rt]*(m>>1); tag[rt]=0; } } void build(int l,int r,int rt) { tag[rt]=0; if(l==r){ scanf("%lld",&sum[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void update(int L,int R,int k,int l,int r,int rt) { if(L<=l&&r<=R){ tag[rt]+=k; sum[rt]+=k*(r-l+1); return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,k,lson); if(R>m) update(L,R,k,rson); push_up(rt); } void get(int l,int r,int rt) { if(l==r){ ans+=(sum[rt]-avg)*(sum[rt]-avg); return; } push_down(rt,r-l+1); int m=(l+r)>>1; get(lson); get(rson); } int main() { //freopen("in.txt","r",stdin); while(~RI(n)){ build(1,n,1); RI(m); while(m--){ RIII(l,r,k); update(l+1,r,-k,1,n,1); } avg=(ll)(sum[1]*1.0/n); ans=0; get(1,n,1); cout<<ans<<endl; } return 0; }
hihocoder1068:
RMQ问题(区间最小值查询)。用线段树直接秒了。。。
http://hihocoder.com/problemset/problem/1068
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int N,M; int Min[maxn<<2]; int a,b; void push_up(int rt) { Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r){ RI(Min[rt]); return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return Min[rt]; int m=(l+r)>>1; int res=INF; if(L<=m) res=min(res,query(L,R,lson)); if(R>m) res=min(res,query(L,R,rson)); return res; } int main() { freopen("in.txt","r",stdin); cin>>N; build(1,N,1); cin>>M; while(M--){ RII(a,b); printf("%d\n",query(a,b,1,N,1)); } return 0; }
D题:
离散化,区间更新,全区间的最终状态。
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/D
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=40100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 PII post[maxn]; int n; int p[maxn],cnt,m; int col[maxn<<2]; //map<int,int> id; bool vis[maxn<<2]; int ans; void push_down(int rt) { if(col[rt]){ col[rt<<1]=col[rt<<1|1]=col[rt]; col[rt]=0; } } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ col[rt]=c; return; } push_down(rt); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); } int query(int l,int r,int rt) { if(col[rt]){ if(!vis[col[rt]]){ vis[col[rt]]=1; return 1; } return 0; } if(l==r) return 0; int m=(l+r)>>1; return query(lson)+query(rson); } int main() { freopen("in.txt","r",stdin); DRI(T); while(T--){ RI(n); cnt=0; REP(i,1,n){ RII(post[i].fst,post[i].snd); p[++cnt]=post[i].fst; p[++cnt]=post[i].snd; } sort(p+1,p+cnt+1); m=1; REP(i,2,cnt){ if(p[i]!=p[i-1]) p[++m]=p[i]; } sort(p+1,p+m+1); cnt=m; REP(i,2,cnt){ if(p[i]-p[i-1]>1) p[++m]=p[i]-1; } sort(p+1,p+m+1); //id.clear(); //REP(i,1,m) id[p[i]]=i; MS0(col); REP(i,1,n){ //int L=id[post[i].fst]; //int R=id[post[i].snd]; int L=lower_bound(p+1,p+m+1,post[i].fst)-p; int R=lower_bound(p+1,p+m+1,post[i].snd)-p; update(L,R,i,1,m,1); } MS0(vis); cout<<query(1,m,1)<<endl; } return 0; }
F题:
区间更新,全区间的最终状态。统计连续的区间,最后压出最终状态统计即可。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int N=8010; int col[maxn<<2]; int n; int a,b,c; int cnt[maxn]; int color[maxn]; void push_down(int rt) { if(col[rt]){ col[rt<<1]=col[rt<<1|1]=col[rt]; col[rt]=0; } } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ col[rt]=c; return; } push_down(rt); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); } void query(int l,int r,int rt) { if(l==r){ color[l]=col[rt]; return; } push_down(rt); int m=(l+r)>>1; query(lson); query(rson); } int main() { //freopen("in.txt","r",stdin); while(~RI(n)){ MS0(col); REP(i,1,n){ RIII(a,b,c); a++,b++,c++; b--; update(a,b,c,1,N-1,1); } MS0(cnt); MS0(color); query(1,N-1,1); cnt[color[1]]++; REP(i,2,N-1){ if(color[i]!=color[i-1]&&color[i]) cnt[color[i]]++; } REP(i,1,N-1) if(cnt[i]) printf("%d %d\n",i-1,cnt[i]); puts(""); } return 0; }
G题:
区间最值,水题。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int n,q; int Max[maxn<<2],Min[maxn<<2]; void push_up(int rt) { Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r){ RI(Max[rt]); Min[rt]=Max[rt]; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } int queryMax(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return Max[rt]; int m=(l+r)>>1; int res=-INF; if(L<=m) res=max(queryMax(L,R,lson),res); if(R>m) res=max(queryMax(L,R,rson),res); return res; } int queryMin(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return Min[rt]; int m=(l+r)>>1; int res=INF; if(L<=m) res=min(queryMin(L,R,lson),res); if(R>m) res=min(queryMin(L,R,rson),res); return res; } int main() { freopen("in.txt","r",stdin); while(~RII(n,q)){ build(1,n,1); while(q--){ DRII(x,y); //cout<<queryMax(x,y,1,n,1)<<" "<<queryMin(x,y,1,n,1)<<endl; printf("%d\n",queryMax(x,y,1,n,1)-queryMin(x,y,1,n,1)); } } return 0; }
H题:
区间更新(变为原来的开方),区间求和。
由于开方和区间和并没有什么联系(这一点和区间增减替换不同),所以直接搞无法记录每次更新后的和,延迟标记也没什么用,肯定超时。
然而注意到一个64位整数最多只能开方十几次,之后就变为1了,因此,另开一个bool数组one[maxn<<2]记录某区间是否全为1,这样更新和查询的时候碰到全为1的区间就不必再更新以及查询其子结点了。
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/H
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned __int64 #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int n; ll sum[maxn<<2]; bool one[maxn<<2]; int op,a,b; void push_up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; one[rt]=one[rt<<1]&one[rt<<1|1]; } void build(int l,int r,int rt) { one[rt]=0; if(l==r){ scanf("%I64d\n",&sum[rt]); if(sum[rt]==1) one[rt]=1; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void update(int L,int R,int l,int r,int rt) { if(one[rt]) return; if(l==r){ sum[rt]=(ll)sqrt(sum[rt]*1.0); if(sum[rt]==1) one[rt]=1; return; } int m=(l+r)>>1; if(L<=m) update(L,R,lson); if(R>m) update(L,R,rson); push_up(rt); } ll query(int L,int R,int l,int r,int rt) { if(one[rt]){ return min(R,r)-max(L,l)+1; } if(L<=l&&r<=R) return sum[rt]; if(l==r) return sum[rt]; int m=(l+r)>>1; ll res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } int main() { // freopen("in.txt","r",stdin); int casen=1; while(~RI(n)){ build(1,n,1); DRI(m); printf("Case #%d:\n",casen++); while(m--){ RIII(op,a,b); if(a>b) swap(a,b); if(op) printf("%I64d\n",query(a,b,1,n,1)); else update(a,b,1,n,1); } puts(""); } return 0; }
poj3667:
区间合并。查询最左边的长度不小于c的第一个区间的左端点。开三个数组分别存最左区间,最右区间,最长区间,查询时贪心地先向左子结点查询。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int N,M; int msum[maxn],lsum[maxn],rsum[maxn]; int cover[maxn]; int op,a,b; void push_up(int rt,int m) { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(msum[rt<<1],msum[rt<<1|1])); } void push_down(int rt,int m) { if(cover[rt]!=-1){ cover[rt<<1]=cover[rt<<1|1]=cover[rt]; msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?0:(m-(m>>1)); msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cover[rt]?0:(m>>1); cover[rt]=-1; } } void build(int l,int r,int rt) { cover[rt]=-1; msum[rt]=lsum[rt]=rsum[rt]=r-l+1; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ cover[rt]=c; msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1; return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); push_up(rt,r-l+1); } int query(int w,int l,int r,int rt) { if(l==r) return l; push_down(rt,r-l+1); int m=(l+r)>>1; if(msum[rt<<1]>=w) return query(w,lson); else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1; return query(w,rson); } int main() { freopen("in.txt","r",stdin); while(~RII(N,M)){ build(1,N,1); while(M--){ RI(op); if(op==1){ RI(a); if(msum[1]<a) puts("0"); else{ int p=query(a,1,N,1); printf("%d\n",p); update(p,p+a-1,1,1,N,1); } } else RII(a,b),update(a,a+b-1,0,1,N,1); } } return 0; }
I题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/I
区间合并。查询某点所在的位置的最长连续区间的长度。开两个数组存最左区间和最右区间。p所在区间=(p-1)向左边延伸的最长区间+(p+1)向右延伸的最长区间+1,查x向右延伸区间时,取区间中点m,若x在左子结点上,则判断p是否在左子结点的最右区间上,如果在,ans=从p到左子结点区间右端点+右子结点左区间,自行画图脑补。。如果不在,问题就变成了查询x在左子结点区间的向右延伸的最长区间,重复了上述过程,递归解决。若x在右子结点上,同样重复了上述过程,递归解决。
注意:如果查询的p是1或者n,只查一边即可,查两边就会发生错误,所以加上特判即可。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int lsum[maxn<<2],rsum[maxn<<2]; int tag[maxn<<2]; bool val[maxn]; int n,q; char op; int a; stack<int> s; void push_up(int rt,int m) { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; } void push_down(int rt,int m) { if(tag[rt]!=-1){ tag[rt<<1]=tag[rt<<1|1]=tag[rt]; lsum[rt<<1]=rsum[rt<<1]=tag[rt]?0:(m-(m>>1)); lsum[rt<<1|1]=rsum[rt<<1|1]=tag[rt]?0:(m>>1); tag[rt]=-1; } } void build(int l,int r,int rt) { tag[rt]=-1; if(l==r){ lsum[rt]=rsum[rt]=1; val[l]=0; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt,r-l+1); } void update(int p,int c,int l,int r,int rt) { if(l==r){ tag[rt]=c; lsum[rt]=rsum[rt]=c?0:1; return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(p<=m) update(p,c,lson); else update(p,c,rson); push_up(rt,r-l+1); } int queryL(int p,int l,int r,int rt) { if(p==l) return lsum[rt]; push_down(rt,r-l+1); int m=(l+r)>>1; if(p<=m){ if(p+rsum[rt<<1]-1>=m) return m-p+1+lsum[rt<<1|1]; return queryL(p,lson); } return queryL(p,rson); } int queryR(int p,int l,int r,int rt) { if(p==r) return rsum[rt]; push_down(rt,r-l+1); int m=(l+r)>>1; if(p>m){ if(m+lsum[rt<<1|1]>=p) return p-m+rsum[rt<<1]; return queryR(p,rson); } return queryR(p,lson); } int main() { freopen("in.txt","r",stdin); while(~RII(n,q)){ while(!s.empty()) s.pop(); build(1,n,1); while(q--){ cin>>op; if(op=='D'){ RI(a); val[a]=1; update(a,1,1,n,1); s.push(a); } else if(op=='Q'){ RI(a); if(val[a]) puts("0"); else if(a==1) printf("%d\n",queryL(a+1,1,n,1)+1); else if(a==n) printf("%d\n",queryR(a-1,1,n,1)+1); else printf("%d\n",queryR(a-1,1,n,1)+queryL(a+1,1,n,1)+1); } else{ if(!s.empty()){ int u=s.top(); s.pop(); val[u]=0; update(u,0,1,n,1); } } } } return 0; }
J题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/J
逆向并查集的题目,偏偏要用线段树做。。。(类似某省赛题)
题意:给定一颗树,初始化每个结点的值为-1,q次询问或修改,每次修改某一个结点则须将其所有子结点以及子结点的子结点都修改,询问则询问某结点的值。
思路:首先dfs给原树的结点标上区间及编号,用区间左端点来表示结点的编号,所以标区间时要预留一个左端点给该结点,其余的分给子结点。然后强行另建一颗线段树。。。最后就是基础的区间修改和单点查询了。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int N; int deg[maxn]; vector<int> G[maxn]; int u,v; int root; int li[maxn],ri[maxn],cnt; char op; ll x,y; ll tag[maxn<<2]; ll val[maxn<<2]; void dfs(int u,int num) { li[u]=++cnt; REP(i,0,SZ(G[u])-1){ int v=G[u][i]; dfs(v,cnt); } ri[u]=cnt; } void push_down(int rt,int m) { if(tag[rt]!=-1){ tag[rt<<1]=tag[rt<<1|1]=tag[rt]; val[rt<<1]=val[rt<<1|1]=val[rt]; tag[rt]=-1; } } void build(int l,int r,int rt) { tag[rt]=-1; val[rt]=-1; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,ll c,int l,int r,int rt) { if(L<=l&&r<=R){ val[rt]=tag[rt]=c; return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); } ll query(int p,int l,int r,int rt) { if(l==r) return val[rt]; push_down(rt,r-l+1); int m=(l+r)>>1; if(p<=m) return query(p,lson); return query(p,rson); } int main() { freopen("in.txt","r",stdin); DRI(T); REP(casen,1,T){ RI(N); MS0(deg); REP(i,0,N) G[i].clear(); REP(i,1,N-1){ RII(u,v); G[v].PB(u); deg[u]++; } REP(i,1,N) if(!deg[i]) root=i; cnt=0; dfs(root,1); build(1,N,1); DRI(q); printf("Case #%d:\n",casen); while(q--){ cin>>op; if(op=='T'){ cin>>x>>y; update(li[x],ri[x],y,1,N,1); } else{ cin>>x; cout<<query(li[x],1,N,1)<<endl; } } } return 0; }
K题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/K
题意:所有数初始化为0,q次询问或修改。
修改有三种操作,给[L,R]区间的数+c,*c,替换为c。询问区间数的和或平方和或立方和。
思路:线段树中每个结点记录区间的平均值val,区间的数都相同时平均值为val,否则为-1(即没有平均值)。然后对平均值进行更新,区间合并时判断左右子区间的平均值是否存在以及是否相等。区间分解时父区间的val改为-1。每次分解后合并即可。
查询时如果区间平均值存在,直接用val的p次方乘以区间长度(r-l+1)即可,不存在就一直查询下去。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); const ll MOD=10007; struct Node { ll val; }; Node node[maxn<<2]; int n,q; int op,x,y,c; ll qpow(ll n,ll k,ll p) { ll res=1; while(k){ if(k&1) res=((res%p)*(n%p))%p; n=((n%p)*(n%p))%p; k>>=1; } return res; } void push_up(int rt,int m) { if(node[rt<<1].val==-1||node[rt<<1|1].val==-1||node[rt<<1].val!=node[rt<<1|1].val){ node[rt].val=-1; } else{ node[rt].val=node[rt<<1].val; } } void push_down(int rt,int m) { if(node[rt].val!=-1){ node[rt<<1].val=node[rt<<1|1].val=node[rt].val; return; } } void build(int l,int r,int rt) { if(l==r){ node[rt].val=0; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt,r-l+1); } void update(int L,int R,ll c,int op,int l,int r,int rt) { while(L<=l&&r<=R){ if(op==3){ node[rt].val=c%MOD; } else if(op==1){ if(node[rt].val!=-1){ node[rt].val=(node[rt].val+c)%MOD; } else{ push_down(rt,r-l+1); int m=(l+r)>>1; update(L,R,c,op,lson); update(L,R,c,op,rson); push_up(rt,r-l+1); } } else{ if(node[rt].val!=-1){ node[rt].val=((node[rt].val%MOD)*(c%MOD))%MOD; } else{ push_down(rt,r-l+1); int m=(l+r)>>1; update(L,R,c,op,lson); update(L,R,c,op,rson); push_down(rt,r-l+1); } } return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,op,lson); if(R>m) update(L,R,c,op,rson); push_up(rt,r-l+1); } ll query(int L,int R,int p,int l,int r,int rt) { if(L<=l&&r<=R){ if(node[rt].val!=-1){ int t=node[rt].val; return (qpow(t,p,MOD)*((r-l+1)%MOD))%MOD; } else{ push_down(rt,r-l+1); int m=(l+r)>>1; ll res=(query(L,R,p,lson)+query(L,R,p,rson))%MOD; push_up(rt,r-l+1); return res; } } push_down(rt,r-l+1); int m=(l+r)>>1; ll res=0; if(L<=m) res=(query(L,R,p,lson)+res%MOD)%MOD; if(R>m) res=(query(L,R,p,rson)+res%MOD)%MOD; push_up(rt,r-l+1); return res%MOD; } int main() { freopen("in.txt","r",stdin); while(~RII(n,q)){ if(n==0&&q==0) break; build(1,n,1); while(q--){ RI(op);RIII(x,y,c); if(op==4) printf("%d\n",query(x,y,c,1,n,1)); else update(x,y,c,op,1,n,1); } } return 0; }
M题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/M
区间合并。
这题总算是调出来了。。写了一晚上暴力对拍终于找到数据调试成功了。。。
两个易错点:
1,合并时容易把m写成m>>1。
2,还是合并时,node[rt].dms=max(node[rt<<1].drs+node[rt<<1|1].dls,max(node[rt<<1].dms,node[rt<<1|1].dms));,注意后面是取左右子结点区间的最大区间的最大,而不是取左右端区间的最大。
充满debug信息的代码。。。。
总之,没有AC不了的题,只有不努力的ACMER!
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int maxn=1000100; const int INF=(1<<29); int T; int N,Q; struct Node { int dls,drs,dms; int tag1; int nls,nrs,nms; int tag2; }; Node node[maxn<<2]; char op[10]; int D,L,R; void push_up(int rt,int m) { node[rt].dls=node[rt<<1].dls; node[rt].drs=node[rt<<1|1].drs; if(node[rt].dls==(m-(m>>1))) node[rt].dls+=node[rt<<1|1].dls; if(node[rt].drs==(m>>1)) node[rt].drs+=node[rt<<1].drs; node[rt].dms=max(node[rt<<1].drs+node[rt<<1|1].dls,max(node[rt<<1].dms,node[rt<<1|1].dms)); if(node[rt].dms==m) node[rt].tag1=1; else if(node[rt].dms==0) node[rt].tag1=0; else node[rt].tag1=-1; node[rt].nls=node[rt<<1].nls; node[rt].nrs=node[rt<<1|1].nrs; if(node[rt].nls==(m-(m>>1))) node[rt].nls+=node[rt<<1|1].nls; if(node[rt].nrs==(m>>1)) node[rt].nrs+=node[rt<<1].nrs; node[rt].nms=max(node[rt<<1].nrs+node[rt<<1|1].nls,max(node[rt<<1].nms,node[rt<<1|1].nms)); if(node[rt].nms==m) node[rt].tag2=1; else if(node[rt].nms==0) node[rt].tag2=0; else node[rt].tag2=-1; } void push_down(int rt,int m) { if(node[rt].tag1!=-1){ node[rt<<1].tag1=node[rt<<1|1].tag1=node[rt].tag1; node[rt<<1].dls=node[rt<<1].drs=node[rt<<1].dms=node[rt].tag1?(m-(m>>1)):0; node[rt<<1|1].dls=node[rt<<1|1].drs=node[rt<<1|1].dms=node[rt].tag1?(m>>1):0; node[rt].tag1=-1; // if(rt==4) cout<<"rt4= "<<(m-(m>>1))<<" "<<node[rt<<1].dms<<endl; } if(node[rt].tag2!=-1){ node[rt<<1].tag2=node[rt<<1|1].tag2=node[rt].tag2; node[rt<<1].nls=node[rt<<1].nrs=node[rt<<1].nms=node[rt].tag2?(m-(m>>1)):0; node[rt<<1|1].nls=node[rt<<1|1].nrs=node[rt<<1|1].nms=node[rt].tag2?(m>>1):0; node[rt].tag2=-1; } } void build(int l,int r,int rt) { // cout<<"l="<<l<<" r="<<r<<" rt="<<rt<<endl; if(l==r){ node[rt].dls=node[rt].drs=node[rt].dms=node[rt].nls=node[rt].nrs=node[rt].nms=1; node[rt].tag1=-1; node[rt].tag2=-1; return; } push_down(rt,r-l+1); int m=(l+r)>>1; build(lson); build(rson); push_up(rt,r-l+1); } int queryD(int D,int l,int r,int rt) { // cout<<"l="<<l<<" r="<<r<<" m="<<((l+r)>>1)<<" D="<<D<<" rt="<<rt<<" "<<node[rt].tag1<<endl; // cout<<":rt="<<rt<<" dls="<<node[rt].dls<<" dms="<<node[rt].dms<<" "<<D<<endl; if(node[rt].dls>=D) return l; push_down(rt,r-l+1); int m=(l+r)>>1; // cout<<":::"<<(rt<<1)<<" "<<node[rt<<1].dms<<endl; if(node[rt<<1].dms>=D) return queryD(D,lson); if(node[rt<<1].drs+node[rt<<1|1].dls>=D) return m-node[rt<<1].drs+1; return queryD(D,rson); } int queryN(int D,int l,int r,int rt) { if(node[rt].nls>=D) return l; push_down(rt,r-l+1); int m=(l+r)>>1; if(node[rt<<1].nms>=D) return queryN(D,lson); if(node[rt<<1].nrs+node[rt<<1|1].nls>=D) return m-node[rt<<1].nrs+1; return queryN(D,rson); } void update(int L,int R,int op,int l,int r,int rt) { // cout<<"l="<<l<<" r="<<r<<endl; if(L<=l&&r<=R){ if(op==0){ node[rt].dls=node[rt].dms=node[rt].drs=r-l+1; node[rt].nls=node[rt].nms=node[rt].nrs=r-l+1; node[rt].tag1=1; node[rt].tag2=1; } else if(op==1){ //cout<<node[1].dms<<" "<<node[13].dms<<endl; //cout<<"FFF "<<rt<<" "<<l<<" "<<r<<endl; node[rt].dls=node[rt].dms=node[rt].drs=0; node[rt].nls=node[rt].nms=node[rt].nrs=r-l+1; node[rt].tag1=0; node[rt].tag2=1; //cout<<node[rt].dms<<endl; } else if(op==2){ node[rt].dls=node[rt].dms=node[rt].drs=0; node[rt].nls=node[rt].nms=node[rt].nrs=0; node[rt].tag1=node[rt].tag2=0; } return; } push_down(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,op,lson); if(R>m) update(L,R,op,rson); push_up(rt,r-l+1); } /* void get(int l,int r,int rt) { if(l==r){ // cout<<"l:"<<l<<" rt"<<rt<<" "; cout<<node[rt].dms<<" "; return; } push_down(rt,r-l+1); int m=(l+r)>>1; get(lson); get(rson); push_up(rt,r-l+1); } void get2(int l,int r,int rt) { if(l==r){ cout<<node[rt].nms<<" "; return; } push_down(rt,r-l+1); int m=(l+r)>>1; get2(lson); get2(rson); push_up(rt,r-l+1); } */ int main() { freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); cin>>T; int casen=1; while(T--){ cin>>N>>Q; build(1,N,1); printf("Case %d:\n",casen++); while(Q--){ // get(1,N,1);cout<<endl; // get2(1,N,1);cout<<endl; scanf("%s",op); if(op[0]=='S'){ scanf("%d%d",&L,&R); puts("I am the hope of chinese chengxuyuan!!"); update(L,R,0,1,N,1); } else if(op[0]=='D'){ scanf("%d",&D); if(node[1].dms<D) puts("fly with yourself"); else{ //get(1,N,1); int p=queryD(D,1,N,1); printf("%d,let's fly\n",p); //cout<<p<<p+D-1<<endl; // get(1,N,1);cout<<endl; //cout<<node[1].dms<<endl; update(p,p+D-1,1,1,N,1); // cout<<"__"<<node[13].dms<<" "<<node[1].dms<<endl; //get(1,N,1); // cout<<"rt8= "<<node[8].dls<<" "<<node[8].dms<<" "<<node[8].drs<<" "<<node[8].tag1<<endl; } } else{ scanf("%d",&D); //cout<<"n1.dms="<<node[1].dms<<endl; // cout<<node[1].dms<<endl; if(node[1].dms>=D){ int p=queryD(D,1,N,1); // cout<<"F1"<<endl; // cout<<p<<endl; printf("%d,don't put my gezi\n",p); // get(1,N,1); update(p,p+D-1,2,1,N,1); // get(1,N,1); } else if(node[1].nms>=D){ int p=queryN(D,1,N,1); // cout<<"F2"<<endl; printf("%d,don't put my gezi\n",p); //cout<<p<<" "<<p+D-1<<endl; update(p,p+D-1,2,1,N,1); } else puts("wait for me"); } // get(1,N,1);cout<<endl; // cout<<node[1].dms<<endl; } } return 0; }
由于时间关系,后面的扫描线暂时先不搞了。
线段树暂时告一段落,
下一专题:后缀数组。