如果你还是迷迷糊糊的话,建议先休息一下,前方高能!!!
题目链接:点这里
大概意思就是。
给出一个数列,m次操作,序列长度和操作次数都不超过100000。
输入:k l r x
k表示操作类别
操作分两种:
(1)把[l,r]区间的数字都变成x。
(2)把[l,r]区间中比x大的数字变成和x的最大公约数。
输出:
操作后的数组
如果你没学过线段树,你可能会用普通的解法,结果是超时(我试过),那么用线段树如何解呢?
先发着,以后再写吧,不早了。zzz
/*
hdu4902
线段树,书上版本
妙妙妙呀
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mid (r+l>>1)
#define lc (d<<1)
#define rc (d<<1|1)
const int mmax = 100002;
struct tree
{
int lzx;//lazy懒x表示可替代x //感觉可以用bool来替代
int v; //结点值,可替代x
}tr[mmax << 2];
struct queue
{
int k, l, r, x;
}que[mmax];
int val[mmax];
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a%b);
}
void push(int d)//维护最大的,为了后面优化
{
tr[d].v = max(tr[lc].v, tr[rc].v);
}
void build(int d, int l, int r)
{
if (l == r)
{
tr[d].v = val[l];
tr[d].lzx = -1;
return;
}
tr[d].lzx = -1;//放上面和build下面一样
build(lc, l, mid);
build(rc, mid + 1, r);
push(d);
}
void lazy(int d)//懒操作de延伸
{
if (tr[d].lzx != -1)
{
tr[lc].lzx = tr[rc].lzx = tr[d].lzx;
tr[lc].v = tr[rc].v = tr[d].v;
tr[d].lzx = -1;//生效完还原
}
}
void f1(int d, int l, int r, int left, int right, int x)
{
if (l == left && r == right)
{
tr[d].lzx = x;
tr[d].v = x;
return;
}
lazy(d);
if (left > mid) f1(rc, mid + 1, r, left, right, x);//区间在右边
else if (right <= mid) f1(lc, l, mid, left, right, x); //等于只能右边加
else
{
f1(rc, mid + 1, r, mid + 1, right, x);//这里要变一下
f1(lc, l, mid, left, mid, x);
}
push(d);
}
void f2(int d, int l, int r, int left, int right, int x)
{
if (l == left && r == right)
{
if (tr[d].v <= x) return;
if (tr[d].lzx != -1)
{
tr[d].v = gcd(tr[d].v, x);
tr[d].lzx = tr[d].v;
if (l == r) val[l] = tr[d].lzx;//感觉多余
return;
}
if (l == r)//和模板很像
{
if (val[l] > x) val[l] = gcd(val[l], x);
return;
}
lazy(d);
f2(lc, l, mid, left, mid, x);
f2(rc, mid + 1, r, mid + 1, right, x);
push(d);
return;
}
lazy(d);
if (left > mid) f2(rc, mid + 1, r, left, right, x);//区间在右边
else if (right <= mid) f2(lc, l, mid, left, right, x); //等于可以加
else
{
f2(rc, mid + 1, r, mid + 1, right, x);
f2(lc, l, mid, left, mid, x);
}
push(d);
}
void out(int d, int l, int r)
{
if (tr[d].lzx != -1)
{
for (int i = l; i <= r; i++)
{
printf("%d ", tr[d].lzx);//一样的是d
}
return;
}
if (l == r)
{
printf("%d ", val[l]);
return;
}
lazy(d);
out(lc, l, mid);
out(rc, mid + 1, r);
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
//初始化
memset(val, 0, sizeof(val));
//输入
int n1;
scanf("%d", &n1);
for (int i = 1; i <= n1; i++)
{
scanf("%d", &val[i]);
}
build(1, 1, n1);
int n2;
scanf("%d", &n2);
for (int i = 1; i <= n2; i++)
{
scanf("%d%d%d%d", &que[i].k, &que[i].l, &que[i].r, &que[i].x);
}
//处理
for (int i = 1; i <= n2; i++)
{
if (que[i].k == 1)
{
f1(1, 1, n1, que[i].l, que[i].r, que[i].x);
}
else
{
f2(1, 1, n1, que[i].l, que[i].r, que[i].x);
}
/* out(1, 1, n1);
printf("\n");*/
}
out(1, 1, n1);
printf("\n");
}
return 0;
}
下面是我的代码
/*
hdu4902
线段树,自己打的
妙妙妙呀
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lc (d<<1)
#define rc (d<<1|1)
#define mid (l+r>>1)
const int mmax = 100005;
int val[mmax];
struct tree
{
int v;
bool lz;//懒操作标记,lazy简写
}tr[mmax << 2];
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a%b);
}
//懒操作
void lazy(int d)
{
if (tr[d].lz)
{
tr[lc].v = tr[rc].v = tr[d].v;
tr[lc].lz = tr[rc].lz = true;
tr[d].lz = false;
}
}
void push(int d)
{
tr[d].v = max(tr[lc].v, tr[rc].v);
}
void build(int d, int l, int r)
{
if (l == r)
{
tr[d].v = val[l];
tr[d].lz = false;
return;
}
tr[d].lz = false;
build(lc, l, mid);
build(rc, mid + 1, r);
push(d);
}
void f1(int d, int l, int r, int left, int right, int x)
{
if (l == left && r == right)
{
tr[d].lz = true;
tr[d].v = x;
return;
}
lazy(d);
if (left > mid) f1(rc, mid+1, r, left, right, x);
else if (right <= mid) f1(lc, l, mid, left, right, x);
else
{
f1(rc, mid+1, r, mid+1, right, x);
f1(lc, l, mid, left, mid, x);
}
push(d);
}
void f2(int d, int l, int r, int left, int right, int x)
{
if (l == left && r == right)
{
if (tr[d].v <= x) return;
//lazy说明子结点的tr[d].v是一样的,于是处理父结点就可以了
if (tr[d].lz)
{
tr[d].v = gcd(tr[d].v, x);
return;
}
if (l == r)//没有优化的话,只能一个一个点来处理
{
tr[d].v = gcd(tr[d].v, x);
return;
}
lazy(d);
f2(rc, mid+1, r, mid+1, right, x);
f2(lc, l, mid, left, mid, x);
push(d);
return;
}
lazy(d);
if (left > mid) f2(rc, mid+1, r, left, right, x);
else if (right <= mid) f2(lc, l, mid, left, right, x);
else
{
f2(rc, mid+1, r, mid+1, right, x);
f2(lc, l, mid, left, mid, x);
}
push(d);
}
void out(int d, int l, int r)
{
if (tr[d].lz)
{
for (int i = l; i <= r; i++)
{
printf("%d ", tr[d].v);
}
return;
}
if (l == r)
{
printf("%d ", tr[d].v);
return;
}
// lazy(d);
out(lc, l, mid);
out(rc, mid + 1, r);
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n1;
scanf("%d", &n1);
for (int i = 1; i <= n1; i++)
{
scanf("%d", &val[i]);
}
build(1, 1, n1);
int n2;
scanf("%d", &n2);
for (int i = 1; i <= n2; i++)
{
int k, l, r, x;
scanf("%d%d%d%d", &k, &l, &r, &x);
if (k == 1)
{
f1(1, 1, n1, l, r, x);
}
else
{
f2(1, 1, n1, l, r, x);
}
}
out(1, 1, n1);
printf("\n");
}
return 0;
}