Myhchael原創題系列 Mychael vs Kid 【題解】
阿新 • • 發佈:2018-05-28
times using string spa val 情況 加法 經典的 namespace
也就是說,區間差分了之後,我們要求原區間\(gcd[l,r]\),就相當於求\(a_l\)和差分後區間\([l + 1,r]\)的\(gcd\)
所以我們只需維護差分區間和區間每個位置的值即可
題目鏈接
Mychael vs Kid
題解
先說說這題的由來及前身
前身
首先有一個很經典的題目:
維護區間加,查詢區間\(gcd\)
如果強行用線段樹維護的話,區間加之後就沒法直接確定當前區間的\(gcd\),不可直接維護
這個時候就用到了\(gcd\)的一個性質:
\[(a,b) = (a - b,b)\]
三個的\(gcd\)也是符合的:
\[(a,b,c) = (a,b,c - b) = (a,b - a,c - b)\]
同樣可以推廣出\(n\)個的情況
\[gcd\{a_i\} = gcd(a_1,gcd\{a_j - a_{j - 1}\}) \qquad i \in [1,n] \quad j \in [2,n]\]
也就是說,區間差分了之後,我們要求原區間\(gcd[l,r]\),就相當於求\(a_l\)和差分後區間\([l + 1,r]\)的\(gcd\)
所以我們只需維護差分區間和區間每個位置的值即可
維護區間值用線段樹一點問題都沒有
在加法下維護差分區間,一個區間加上一個數,僅影響區間端點的值,所以單點修改即可
所以我們開兩棵線段樹,一棵維護權值,一棵維護差值的\(gcd\),即可\(O(nlog^2n)\)解決這道題
本題
本題多加入了一個區間乘法操作
本來想\(yy\)分塊的,可後來發現線段樹依舊可寫並且暴艹分塊
思考一下發現,區間乘法後,區間差分值也乘上那個數,對應\(gcd\)也乘上一個數,可以使用線段樹維護
至於端點的差值改變,只需取出端點的值計算出差值後單點加法修改即可
復雜度依舊是\(O(nlog^2n)\)
部分分
前\(5\%\),咳,,,
對於\(n,m \le 300\),暴力求即可
對於沒有操作\(2\)的,就是原版題目
對於\(n,m \le 3 \times 10^4\)的,可以考慮分塊
std
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
LL n,m,A[maxn],D[maxn];
LL gcd(LL a,LL b){
if (a < 0) a = -a;
if (b < 0) b = -b;
return b ? gcd(b,a % b) : a;
}
struct Seg_Gcd{
LL Gcd[maxn << 2],tag[maxn << 2];
void upd(int u){
Gcd[u] = gcd(Gcd[ls],Gcd[rs]);
}
void pd(int u){
if (tag[u] != 1){
Gcd[ls] *= tag[u]; tag[ls] *= tag[u];
Gcd[rs] *= tag[u]; tag[rs] *= tag[u];
tag[u] = 1;
}
}
void build(int u,int l,int r){
tag[u] = 1;
if (l == r){
Gcd[u] = D[l];
return;
}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
upd(u);
}
void Add(int u,int l,int r,int pos,int v){
if (l == r){Gcd[u] += v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= pos) Add(ls,l,mid,pos,v);
else Add(rs,mid + 1,r,pos,v);
upd(u);
}
void Mult(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){Gcd[u] *= v; tag[u] *= v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= L) Mult(ls,l,mid,L,R,v);
if (mid < R) Mult(rs,mid + 1,r,L,R,v);
upd(u);
}
LL query(int u,int l,int r,int L,int R){
if (l >= L && r <= R) return Gcd[u];
pd(u);
int mid = l + r >> 1;
if (mid >= R) return query(ls,l,mid,L,R);
if (mid < L) return query(rs,mid + 1,r,L,R);
return gcd(query(ls,l,mid,L,R),query(rs,mid + 1,r,L,R));
}
}T2;
struct Seg{
LL val[maxn << 2],mult[maxn << 2],add[maxn << 2];
void pd(int u){
if (mult[u] != 1){
val[ls] *= mult[u]; mult[ls] *= mult[u]; add[ls] *= mult[u];
val[rs] *= mult[u]; mult[rs] *= mult[u]; add[rs] *= mult[u];
mult[u] = 1;
}
if (add[u]){
val[ls] += add[u]; add[ls] += add[u];
val[rs] += add[u]; add[rs] += add[u];
add[u] = 0;
}
}
void build(int u,int l,int r){
add[u] = 0; mult[u] = 1;
if (l == r){
val[u] = A[l];
return;
}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
}
void Add(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){val[u] += v; add[u] += v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= L) Add(ls,l,mid,L,R,v);
if (mid < R) Add(rs,mid + 1,r,L,R,v);
}
void Mult(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){val[u] *= v; add[u] *= v; mult[u] *= v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= L) Mult(ls,l,mid,L,R,v);
if (mid < R) Mult(rs,mid + 1,r,L,R,v);
}
LL query(int u,int l,int r,int pos){
if (l == r) return val[u];
pd(u);
int mid = l + r >> 1;
if (mid >= pos) return query(ls,l,mid,pos);
return query(rs,mid + 1,r,pos);
}
}T1;
int main(){
n = read(); m = read();
for (int i = 1; i <= n; i++){
A[i] = read();
D[i] = A[i] - A[i - 1];
}
T1.build(1,1,n);
T2.build(1,1,n);
LL opt,l,r,v,t1,t2;
while (m--){
opt = read(); l = read(); r = read();
if (opt == 1){
v = read();
T1.Add(1,1,n,l,r,v);
T2.Add(1,1,n,l,v);
if (r + 1 <= n) T2.Add(1,1,n,r + 1,-v);
}
else if (opt == 2){
v = read();
t1 = T1.query(1,1,n,l);
if (r + 1 <= n) t2 = T1.query(1,1,n,r);
if (l < r) T2.Mult(1,1,n,l + 1,r,v);
T2.Add(1,1,n,l,t1 * v - t1);
if (r + 1 <= n) T2.Add(1,1,n,r + 1,t2 - t2 * v);
T1.Mult(1,1,n,l,r,v);
}
else {
if (l < r) printf("%lld\n",gcd(T1.query(1,1,n,l),T2.query(1,1,n,l + 1,r)));
else printf("%lld\n",T1.query(1,1,n,l));
}
}
return 0;
}
Myhchael原創題系列 Mychael vs Kid 【題解】