一、区间覆盖(将某个区间的所有值变为某个值)+区间查询(求区间和)
题目:HDU1698
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define lowbit(x) x&(-x) #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,r,l) for(int i=r;i>=l;--i) #define ls o<<1 #define rs o<<1|1 #define lson L,mid,ls #define rson mid+1,R,rs using namespace std; typedef long long ll; const int maxn = 1e5+10; const double eps = 1e-8; const double pi = acos(-1.0); int a[maxn]; int sum[maxn<<2],lazy[maxn<<2]; //更新区间o的值 此处为求和,即求左右区间的和 void pushup(int o) { sum[o] = sum[ls]+sum[rs];//o*2 o*2+1 } //建树,o节点为L~R开始往下建树 void build(int L,int R,int o) { lazy[o] = 0; if(L==R) { //初始化操作,开始时最小区间长度均为1 sum[o] = 1; return; } int mid = (R+L)>>1; build(lson); build(rson); //o的左右子树建立好后,向上更新节点o pushup(o); } void pushdown(int o,int len) { if(lazy[o]) { lazy[ls] = lazy[rs] = lazy[o];//lazy向左右节点传递 //左右子区间值更新 因为此处为区间覆盖 所以更新为lazy值*区间长度 sum[ls] = lazy[o]*(len-len/2); sum[rs] = lazy[o]*(len/2); //o节点处lazy已向下传递,重置 lazy[o] = 0; } } //将[l,r]区间的值更新为v,当前区间为[L,R],编号o void update(int l,int r,int L,int R,int o,int v) { if(l<=L&&R<=r) { //找到完全覆盖的区间[L,R],更新[L,R]的值,标记lazy[o] sum[o] = v*(R-L+1); lazy[o] = v; return ; } pushdown(o,R-L+1); int mid = (R+L)>>1; if(l<=mid) update(l,r,lson,v); if(r>mid) update(l,r,rson,v); pushup(o); } //求[l,r]的区间和,当前区间为[L,R],编号o int query(int l,int r,int L,int R,int o) { if(l<=L&&R<=r) return sum[o]; pushdown(o,R-L+1); int mid = (R+L)>>1; int ret = 0; if(l<=mid) ret += query(l,r,lson); if(r>mid) ret += query(l,r,rson); return ret; } int main() { int T; scanf("%d",&T); rep(t,1,T) { int n; scanf("%d",&n); build(1,n,1); int q; scanf("%d",&q); rep(i,1,q) { int l,r,v; scanf("%d %d %d",&l,&r,&v); update(l,r,1,n,1,v); } int ans = query(1,n,1,n,1); printf("Case %d: The total value of the hook is %d. ",t,ans); } }
二、区间更新+区间查询(求区间最大值)
题目:HDU3577
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define lowbit(x) x&(-x) #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,r,l) for(int i=r;i>=l;--i) #define ls o<<1 #define rs o<<1|1 #define lson L,mid,ls #define rson mid+1,R,rs using namespace std; typedef long long ll; const int maxn = 1e6+10; const double eps = 1e-8; const double pi = acos(-1.0); int maxv[maxn<<2],lazy[maxn<<2]; //更新区间o的值 此处为求最大值,即求左右区间的最大值 void pushup(int o) { maxv[o] = max(maxv[ls],maxv[rs]); } //建树,o节点为L~R开始往下建树 void build(int L,int R,int o) { lazy[o] = 0; if(L==R) { //初始化操作,开始时最小区间最大值均为0 maxv[o] = 0; return; } int mid = (R+L)>>1; build(lson); build(rson); //o的左右子树建立好后,向上更新节点o pushup(o); } void pushdown(int o,int len) { if(lazy[o]) { //lazy向左右节点传递 lazy[ls] += lazy[o]; lazy[rs] += lazy[o]; //左右子区间值更新 因为此处为区间值+v 所以更新为 原值+lazy值 maxv[ls] += lazy[o]; maxv[rs] += lazy[o]; //o节点处lazy已向下传递,重置 lazy[o] = 0; } } //将[l,r]区间的值更新为v,当前区间为[L,R],编号o void update(int l,int r,int L,int R,int o,int v) { if(l<=L&&R<=r) { //找到完全覆盖的区间[L,R],更新[L,R]的值(最大值加v),标记lazy[o](lazy+v) maxv[o] += v; lazy[o] += v; return ; } pushdown(o,R-L+1); int mid = (R+L)>>1; if(l<=mid) update(l,r,lson,v); if(r>mid) update(l,r,rson,v); pushup(o); } //求[l,r]的区间最大值,当前区间为[L,R],编号o int query(int l,int r,int L,int R,int o) { if(l<=L&&R<=r) return maxv[o]; pushdown(o,R-L+1); int mid = (R+L)>>1; int ret = 0; //合并左右区间最大值 if(l<=mid) ret = max(ret,query(l,r,lson)); if(r>mid) ret = max(ret,query(l,r,rson)); return ret; } struct node { int l,r; }a[maxn]; int ans[maxn]; int main() { int T; scanf("%d",&T); rep(t,1,T) { int n = 0, k, q; scanf("%d %d", &k, &q); rep(i, 1, q) { scanf("%d %d", &a[i].l, &a[i].r); n = max(n, a[i].r - 1); } build(1, n, 1); int cnt = 0; rep(i, 1, q) { update(a[i].l, a[i].r-1, 1, n, 1, 1); //printf("%d %d ",i,query(a[i].l, a[i].r-1, 1, n, 1)); if (query(a[i].l, a[i].r-1, 1, n, 1) > k) { update(a[i].l, a[i].r-1, 1, n, 1, -1); } else { ans[++cnt] = i; } } printf("Case %d: ", t); rep(i, 1, cnt) { printf("%d ",ans[i]); } printf(" "); } }
三、区间更新+ 区间查询(区间求和)
题目:HDU3468
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define lowbit(x) x&(-x) #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,r,l) for(int i=r;i>=l;--i) #define ls o<<1 #define rs o<<1|1 #define lson L,mid,ls #define rson mid+1,R,rs using namespace std; typedef long long ll; const int maxn = 1e6+10; const double eps = 1e-8; const double pi = acos(-1.0); ll sum[maxn<<2],lazy[maxn<<2]; ll a[maxn]; //更新区间o 的值 此处为求和,即求左右区间的和 void pushup(int o) { sum[o] = sum[ls]+sum[rs]; //maxv[o] = max(maxv[ls],maxv[rs]); } //建树,o 节点为L~R开始往下建树 void build(int L,int R,int o) { lazy[o] = 0; if(L==R) { //初始化操作,开始时最小区间和为本身 sum[o] = a[L]; return; } int mid = (R+L)>>1; build(lson); build(rson); //o 的左右子树建立好后,向上更新节点o pushup(o); } void pushdown(int o,int len) { if(lazy[o]) { //lazy向左右节点传递 lazy[ls] += lazy[o]; lazy[rs] += lazy[o]; //左右子区间值更新 因为此处为区间值+v 所以更新为 原值+lazy值*len sum[ls] += lazy[o]*(len-len/2); sum[rs] += lazy[o]*(len/2); //o节点处lazy已向下传递,重置 lazy[o] = 0; } } //将[l,r]区间的值更新v(+v),当前区间为[L,R],编号o void update(int l,int r,int L,int R,int o,int v) { if(l<=L&&R<=r) { //找到完全覆盖的区间[L,R],更新[L,R]的值(和加上v*len),标记lazy[o](lazy+v) sum[o] += v*(R-L+1); lazy[o] += v; return ; } pushdown(o,R-L+1); int mid = (R+L)>>1; if(l<=mid) update(l,r,lson,v); if(r>mid) update(l,r,rson,v); pushup(o); } //求[l,r]的区间和,当前区间为[L,R],编号o ll query(int l,int r,int L,int R,int o) { if(l<=L&&R<=r) return sum[o]; pushdown(o,R-L+1); int mid = (R+L)>>1; ll ret = 0; //合并左右区间的和 if(l<=mid) ret += query(l,r,lson); if(r>mid) ret += query(l,r,rson); return ret; } int main() { int n,q; scanf("%d %d",&n,&q); rep(i,1,n) { scanf("%lld",&a[i]); } build(1,n,1); rep(i,1,q) { char s[2]; int l,r,x; scanf("%s",s); //printf("%c ",s[0]); if(s[0]=='C') { scanf("%d %d %d",&l,&r,&x); update(l,r,1,n,1,x); //printf("c %d %d %d end ",l,r,x); } if(s[0]=='Q') { scanf("%d %d",&l,&r); //printf("q %d %d ",l,r); printf("%lld ",query(l,r,1,n,1)); } } }
四、离散化+区间覆盖+单点查询(?)效率不够
题目:POJ2528
#include<cstdio> #include<cstring> #include<cmath> #include<set> #include<algorithm> #define lowbit(x) x&(-x) #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,r,l) for(int i=r;i>=l;--i) #define ls o<<1 #define rs o<<1|1 #define lson L,mid,ls #define rson mid+1,R,rs using namespace std; typedef long long ll; const int maxn = 2e4+10; const double eps = 1e-8; const double pi = acos(-1.0); int sum[maxn<<2],lazy[maxn<<2]; //更新区间o 的值 此处为求和,即求左右区间的和 void pushup(int o) { sum[o] = sum[ls]+sum[rs]; //maxv[o] = max(maxv[ls],maxv[rs]); } //建树,o 节点为L~R开始往下建树 void build(int L,int R,int o) { lazy[o] = 0; if(L==R) { //初始化操作,开始时最小区间和为0 sum[o] = 0; return; } int mid = (R+L)>>1; build(lson); build(rson); //o 的左右子树建立好后,向上更新节点o pushup(o); } void pushdown(int o,int len) { if(lazy[o]) { //lazy向左右节点传递 lazy[ls] = lazy[o]; lazy[rs] = lazy[o]; //左右子区间值更新 因为此处为区间覆盖 所以更新为 lazy值*len sum[ls] = lazy[o]*(len-len/2); sum[rs] = lazy[o]*(len/2); //o节点处lazy已向下传递,重置 lazy[o] = 0; } } //将[l,r]区间的值更新为v,当前区间为[L,R],编号o void update(int l,int r,int L,int R,int o,int v) { if(l<=L&&R<=r) { //找到完全覆盖的区间[L,R],更新[L,R]的值(和更新为v*len),标记lazy[o](lazy=v) sum[o] = v*(R-L+1); lazy[o] = v; return ; } pushdown(o,R-L+1); int mid = (R+L)>>1; if(l<=mid) update(l,r,lson,v); if(r>mid) update(l,r,rson,v); pushup(o); } //求[l,r]的区间和,当前区间为[L,R],编号o int query(int l,int r,int L,int R,int o) { if(l<=L&&R<=r) return sum[o]; pushdown(o,R-L+1); int mid = (R+L)>>1; int ret = 0; //合并左右区间的和 if(l<=mid) ret += query(l,r,lson); if(r>mid) ret += query(l,r,rson); return ret; } int a[20010],t[20010]; int main() { int T; scanf("%d",&T); while(T--) { int n = 0, q; scanf("%d", &q); rep(i, 0, q - 1) { scanf("%d %d", &a[2 * i], &a[2 * i + 1]); t[2 * i] = a[2 * i]; t[2 * i + 1] = a[2 * i + 1]; } sort(t, t + 2 * q); int m = unique(t, t + 2 * q) - t - 1; for (int i = 0; i < 2 * q; i++) { //printf("%d %d ",i,a[i]); a[i] = lower_bound(t, t+m, a[i])-t +1; //printf("%d ",a[i]); } rep(i, 0, q - 1) { n = max(n, a[i * 2 + 1]); } //printf("n=%d ", n); build(1, n, 1); //给第i 张海报赋值为i, 贴到对应区间,最后扫一遍区间统计出现的数有多少种就是有多少张海报可见 rep(i, 0, q - 1) { update(a[2 * i], a[2 * i + 1], 1, n, 1, i + 1); } set<int> s; int ans = 0; rep(i, 1, n) { int tmp = query(i, i, 1, n, 1); if (tmp == 0) continue; if (s.find(tmp) == s.end()) { ans++; s.insert(tmp); } } printf("%d ", ans); } }