我只是循规蹈矩地生活,惯于离经叛道,体味心安理得。亦于按部就班,痛感乏善可陈。我欺骗过,伪装过,失真过,但置我于死地者,必将赐我以后生。
这次考试太惨,直接说题目吧。
这道题十分之坑爹,如果只有赋值操作或只有增加操作那十分简单,直接敲区间修改线段树模板就好了。但它要求支持两个操作。
那么我们要这样想。
因为它有两个操作,增值和赋值。那么我们设置两个lazy标记分别表示增值的和赋值的量(代码中我们用value增值,delta赋值)。然后咋整呢?
我们讨论一下,1、原来的线段上有增值标记那么我们进行增值操作的时候之间标记加值就好了。如果是赋值操作那么就覆盖掉原来的增值。等等。。。。
所有讨论如下:
空标记+ 赋值操作= 赋值标记
空标记+ 增量操作= 增量标记
增量标记+ 赋值操作= 赋值标记
增量标记+ 增量操作= 增量标记
赋值标记+ 增量操作= 赋值标记
赋值标记+ 赋值操作= 赋值标记
所以我们再设置一个type表示无标记、增值标记和赋值标记。
代码中我们用0无,1增值,2赋值来表示。
然后就是码代码了,详解见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
#define dnt long long
using namespace std;
int aa[N], n, m, x, y, z;
struct Node;
void change( Node *nd, int lf, int rg, int L, int R, int val );
void modify( Node *nd, int lf, int rg, int L, int R, int val );
struct Node{
dnt sum;
int type;
dnt value, delta;// 0 无 1 增值 2 赋值 value 增值 delta 赋值
Node *ls, *rs;
void pushdown(int lf, int rg) {// pushdown的时候我们讨论type的种类
if ( type == 0 ) return;// 为0 无标记 返回
if ( type == 1 ) { // 1 为增值用change修改
int mid = (lf + rg) >> 1;
change(ls, lf, mid, lf, mid, value);
change(rs, mid+1, rg, mid+1, rg, value);
type = 0;
}
else {// 2 为赋值用modify修改
int mid = (lf + rg) >> 1;
modify(ls, lf, mid, lf, mid, delta);
modify(rs, mid+1, rg, mid+1, rg, delta);
type = 0;
}
}
void update() {
sum = ls->sum + rs->sum;
}
};
Node pool[N * 2], *tail = pool, *root;
Node *build(int lf, int rg) {//普通的建树
Node *nd = ++tail;
if ( lf == rg ) {
nd->sum = aa[lf];
nd->type = 0;
}
else {
int mid = (lf + rg) >> 1;
nd->ls = build(lf, mid);
nd->rs = build(mid+1, rg);
nd->update();
nd->type = 0;
}
return nd;
}
void change( Node *nd, int lf, int rg, int L, int R, int val ) {
if ( L <= lf && rg <= R ) {
nd->sum += (dnt)(rg - lf + 1) * (dnt)val;
if ( nd->type == 0 ) {
nd->type = 1;
nd->value = val; // 注意这里要用赋值,不用 += 因为这里type为0表示无标记所以要重新给值(具体原因是pushdown的时候未清两个lazy标记的值)
}
else if ( nd->type == 1) nd->value += val; // 增值和增值操作标记种类不变,在增值标记上加
else nd->delta += val; // 赋值对增值操作为赋值标记,所以在赋值标记上加
return;
}
else {
nd->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
if ( L <= mid )
change(nd->ls, lf, mid, L, R, val);
if ( R > mid)
change(nd->rs, mid+1, rg, L, R, val);
nd->update();
}
}
void modify( Node *nd, int lf, int rg, int L, int R, int val ) {
if ( L <= lf && rg <= R ) {
nd->sum = (dnt)(rg - lf + 1) * (dnt)val;
nd->type = 2;// 赋值操作直接变成2 十分的霸道~~~
nd->delta = val; //赋值标记改变
return;
}
else {
nd->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
if ( L <= mid )
modify(nd->ls, lf, mid, L, R, val);
if ( R > mid)
modify(nd->rs, mid+1, rg, L, R, val);
nd->update();
}
}
dnt query( Node *nd, int lf, int rg, int L, int R ) {//普通的查询
dnt rt = 0;
if ( L <= lf && rg <= R ) {
return nd->sum;
}
int mid = (lf + rg) >> 1;
nd->pushdown(lf , rg);
if ( L <= mid ) rt += query(nd->ls, lf, mid, L, R);
if ( R > mid ) rt += query(nd->rs, mid+1, rg, L, R);
// nd->update();
return rt;
}
int main() {
freopen("setmod.in","r",stdin);
freopen("setmod.out","w",stdout);
scanf( "%d%d", &n, &m );
for ( int i = 1; i <= n; i++ )
scanf( "%d", &aa[i] );
root = build(1, n);
for ( int i = 1; i <= m; i++ ) {// x > y 左端大于右端非法情况。
char s[10];
scanf( "%s", s );
if ( s[0] == 'c' ) {
scanf( "%d%d%d", &x, &y, &z );
if ( x > y ) continue;
change(root, 1, n, x, y, z);
}
if ( s[0] == 'q' ) {
scanf( "%d%d", &x, &y );
if ( x > y ) {
printf("0\n");
continue;
}
printf( "%I64d\n", query(root, 1, n, x, y) );
}
if ( s[0] == 'm' ) {
scanf( "%d%d%d", &x, &y, &z );
if ( x > y ) continue;
modify(root, 1, n, x, y, z);
}
}
return 0;
}
模板题:动态主席树(用树状数组套值域线段树实现)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define dnt long long
#define clear(a) memset(a, 0, sizeof(a))
#define N 100005
#define lowbit(x) x & -x
using namespace std;
int n, m, aa[N], ca, cb, x, y, k;
char s[10];
struct Node{
int siz;
Node *ls, *rs;
};
struct Node pool[200 * N], *tail = pool, *roots[N], *null;
struct Node *va[N], *vb[N];
Node *newnode() {
Node *nd = ++tail;
nd->ls = null;
nd->rs = null;
nd->siz = 0;
return nd;
}
void init() {
null = ++tail;
null->ls = null;
null->rs = null;
null->siz = 0;
}
void modify( int lf, int rg, int pos, int delta ) {
for ( int i = 1; i <= ca; i++ )
va[i]->siz += delta;
if ( lf == rg ) return;
int mid = (lf + rg) >> 1;
if ( pos <= mid ) {
for ( int i = 1; i <= ca; i++ ) {
if ( va[i]->ls == null )
va[i]->ls = newnode();
va[i] = va[i]->ls;
}
modify(lf, mid, pos, delta);
}
else {
for ( int i = 1; i <= ca; i++ ) {
if ( va[i]->rs == null )
va[i]->rs = newnode();
va[i] = va[i]->rs;
}
modify(mid+1, rg, pos, delta);
}
}
void modify( int u, int pos, int delta ) {
ca = 0;
for ( int i = u; i <= n; i += lowbit(i) )
va[++ca] = roots[i];
modify(1, n, pos, delta);
}
void modify( int u, int val ) {
modify( u, aa[u], -1 );
modify( u, val, 1 );
aa[u] = val;
}
int query_seg( int lf, int rg, int k ) {
if ( lf == rg ) return lf;
int lz = 0;
for ( int i = 1; i <= ca; i++ ) lz -= va[i]->ls->siz;
for ( int i = 1; i <= cb; i++ ) lz += vb[i]->ls->siz;
int mid = (lf + rg) >> 1;
if ( k <= lz ) {
for ( int i = 1; i <= ca; i++ )
va[i] = va[i]->ls;
for ( int i = 1; i <= cb; i++ )
vb[i] = vb[i]->ls;
return query_seg(lf, mid, k);
}
else {
for ( int i = 1; i <= ca; i++ )
va[i] = va[i]->rs;
for ( int i = 1; i <= cb; i++ )
vb[i] = vb[i]->rs;
k -= lz;
return query_seg(mid+1, rg, k);
}
}
int query( int l, int r, int k ) {
ca = cb = 0;
for ( int i = l-1; i; i -= lowbit(i) ) va[++ca] = roots[i];
for ( int i = r; i; i -= lowbit(i) ) vb[++cb] = roots[i];
return query_seg(1, n, k);
}
int main() {
scanf( "%d%d", &n, &m );
for ( int i = 1; i <= n; i++ )
scanf( "%d", &aa[i] );
init();
for ( int i = 0; i <= n; i++ )
roots[i] = newnode();
for ( int i = 1; i <= n; i++ )
modify(i, aa[i], 1);
while ( m-- ) {
scanf( "%s", s );
if ( s[0] == 'm' ) {
scanf( "%d%d", &x, &y );
modify( x, y );
}
else {
scanf( "%d%d%d", &x, &y, &k );
printf( "%d\n", query(x, y, k) );
}
}
return 0;
}
思念着你