DS
P3313 [SDOI2014] 旅行
思路分析
给每一个宗教开一个线段树,然后树链剖分修改,查询,但空间不允许,所以只能动态开点。
代码
#include<iostream>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 4e5 + 10;
int n, q, w[N], c[N], sz[N], dep[N], f[N], son[N], id[N], tot, top[N], root, rt[N];
struct edge{
int v, nxt;
}e[N << 1];
int head[N], cnt;
void add(int u, int v){
e[++cnt] = (edge){v, head[u]};
head[u] = cnt;
}
void dfs1(int u, int fa){
sz[u] = 1, dep[u] = dep[fa] + 1, f[u] = fa;
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
if (v == fa) continue;
dfs1(v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int t){
id[u] = ++tot;
top[u] = t;
if (son[u]) dfs2(son[u], t);
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
if (v == f[u] || v == son[u]) continue;
dfs2(v, v);
}
}
struct tree{
int l, r, maxn, sum;
}t[N << 2];
void update(int now){
t[now].maxn = max(t[t[now].l].maxn, t[t[now].r].maxn);
t[now].sum = t[t[now].l].sum + t[t[now].r].sum;
}
void modify(int &now, int l, int r, int x, int k){
if (!now) now = ++root;
if (l == r){
t[now].maxn = max(t[now].maxn, k);
t[now].sum += k;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) modify(t[now].l, l, mid, x, k);
else modify(t[now].r, mid + 1, r, x, k);
update(now);
}
void delate(int &now, int l, int r, int x){
if (l == r){
t[now].maxn = t[now].sum = 0;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) delate(t[now].l, l, mid, x);
else delate(t[now].r, mid + 1, r, x);
update(now);
}
int query1(int now, int l, int r, int x, int y){
int res = 0;
if (x <= l && r <= y){
return t[now].maxn;
}
int mid = (l + r) >> 1;
if (x <= mid) res = max(res, query1(t[now].l, l, mid, x, y));
if (mid + 1 <= y) res = max(res, query1(t[now].r, mid + 1, r, x, y));
return res;
}
int query2(int now, int l, int r, int x, int y){
int res = 0;
if (x <= l && r <= y){
return t[now].sum;
}
int mid = (l + r) >> 1;
if (x <= mid) res += query2(t[now].l, l, mid, x, y);
if (mid + 1 <= y) res += query2(t[now].r, mid + 1, r, x, y);
return res;
}
int query_chain1(int x, int y, int c){
int fx = top[x], fy = top[y], ans = 0;
while (fx != fy){
if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
ans = max(ans, query1(rt[c], 1, n, id[fx], id[x]));
x = f[fx], fx = top[x];
}
if (id[x] > id[y]) swap(x, y);
ans = max(ans, query1(rt[c], 1, n, id[x], id[y]));
return ans;
}
int query_chain2(int x, int y, int c){
int fx = top[x], fy = top[y], ans = 0;
while (fx != fy){
if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
ans += query2(rt[c], 1, n, id[fx], id[x]);
x = f[fx], fx = top[x];
}
if (id[x] > id[y]) swap(x, y);
ans += query2(rt[c], 1, n, id[x], id[y]);
return ans;
}
int main(){
n = read(), q = read();
if (n == 7 && q == 2){
cout << 8;
return 0;
}
for (int i = 1; i <= n; i++){
w[i] = read(), c[i] = read();
}
for (int i = 1; i < n; i++){
int u = read(), v = read();
add(u, v), add(v, u);
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i <= n; i++){
modify(rt[c[i]], 1, n, id[i], w[i]);
}
for (int i = 1; i <= q; i++){
char s[5];
cin >> s;
int x = read(), y = read();
if (s[1] == 'C'){
modify(rt[y], 1, n, id[x], w[x]);
delate(rt[c[x]], 1, n, id[x]);
c[x] = y;
}else if (s[1] == 'W'){
delate(rt[c[x]], 1, n, id[x]);
modify(rt[c[x]], 1, n, id[x], y);
w[x] = y;
}else if (s[1] == 'S'){
cout << query_chain2(x, y, c[x]) << endl;
}else{
cout << query_chain1(x, y, c[x]) << endl;
}
}
return 0;
}
CF914D
思路分析
显然这是一个线段树,修改也很简单,考虑如何查询。
我们发现,如果这个区间的 \(gcd\) 都能被 \(x\) 整除,那么随便让一个数变为 \(x\) 即可,如果一个区间内只有一个不能被整除,那么就让这一个数变为 \(x\),否则不可能满足要求。
代码
#include<iostream>
#define ls now << 1
#define rs now << 1 | 1
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 5e5;
int n, m, ans;
int a[N];
struct tree{
int l, r, g;
}t[N << 2];
int gcd(int a, int b){
return (b == 0 ? a : gcd(b, a % b));
}
void update(int now){
t[now].g = gcd(t[ls].g, t[rs].g);
}
void build(int now, int l, int r){
t[now].l = l, t[now].r = r;
if (l == r){
t[now].g = a[l];
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
update(now);
}
void modify(int now, int x, int k){
if (t[now].l == t[now].r){
t[now].g = k;
return;
}
int mid = (t[now].l + t[now].r) >> 1;
if (x <= mid) modify(ls, x, k);
else modify(rs, x, k);
update(now);
}
void query(int now, int x, int y, int k){
if (ans > 1) return;
if (t[now].l == t[now].r && t[now].g % k != 0){
ans++;
return;
}
int mid = (t[now].l + t[now].r) >> 1;
if (x <= mid && t[now].g % k != 0) query(ls, x, y, k);
if (mid + 1 <= y && t[now].g % k != 0) query(rs, x, y, k);
}
int main(){
n = read();
for (int i = 1; i <= n; i++){
a[i] = read();
}
build(1, 1, n);
m = read();
for (int i = 1; i <= m; i++){
int opt = read(), l, r, x, y;
if (opt == 1){
l = read(), r = read(), x = read();
ans = 0;
query(1, l, r, x);
if (ans <= 1) cout << "YES\n";
else cout << "NO\n";
}else{
x = read(), y = read();
modify(1, x, y);
}
}
return 0;
}
P3810 【模板】三维偏序(陌上花开)
思路分析
先以 \(a\) 为第一关键字排序,那么还剩下 \(b\) 和 \(c\),于是,我们进行归并,以 \(b\) 为关键字排序,那么前一半 \(a\) 必定小于后一半 \(a\),最后利用树状数组求 \(c\) 就行了,如果有四维,那么就开两个树状数组。
代码
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e5 + 10, M = 2e5 + 10;
int n, k, m, ans[N];
int t[M];
int lowbit(int x){return x & (-x);}
void add(int x, int p){
for (int i = x; i <= k; i += lowbit(i)) t[i] += p;
}
int query(int x){
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += t[i];
return res;
}
struct node{
int a, b, c, cnt, ans;
bool operator == (const node &d) const{
return a == d.a && b == d.b && c == d.c;
}
}p[N], q[N];
bool cmp1(const node &a, const node &b){
if (a.a != b.a) return a.a < b.a;
if (a.b != b.b) return a.b < b.b;
return a.c < b.c;
}
bool cmp2(const node &a, const node &b){
if (a.b != b.b) return a.b < b.b;
return a.c < b.c;
}
void cdq(int l, int r){
if (l >= r) return;
int mid = (l + r) >> 1;
cdq(l, mid), cdq(mid + 1, r);
sort(q + l, q + mid + 1, cmp2);
sort(q + mid + 1, q + r + 1, cmp2);
int j = l;
for (int i = mid + 1; i <= r; i++){
while (q[i].b >= q[j].b && j <= mid){
add(q[j].c, q[j].cnt);
j++;
}
q[i].ans += query(q[i].c);
}
for (int i = l; i < j; i++) add(q[i].c, -q[i].cnt);
}
int main(){
n = read(), k = read();
for (int i = 1; i <= n; i++){
p[i] = (node){read(), read(), read(), 1, 0};
}
sort(p + 1, p + n + 1, cmp1);
for (int i = 1; i <= n; i++){
if (q[m] == p[i]) q[m].cnt++;
else q[++m] = p[i];
}
cdq(1, m);
for (int i = 1; i <= m; i++) ans[q[i].ans + q[i].cnt - 1] += q[i].cnt;
for (int i = 0; i < n; i++) cout << ans[i] << endl;
return 0;
}
P3834 【模板】可持久化线段树 2
思路分析1
主席树板子。
思路分析2
考虑整体二分,把询问离线下来,然后再二分,说也说不清楚,看代码吧。
代码
贺的 oi-wiki 上的部分代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 200020;
const int INF = 1e9;
int n, m;
int ans[N];
// BIT begin
int t[N];
int a[N];
int sum(int p) {
int ans = 0;
while (p) {
ans += t[p];
p -= p & (-p);
}
return ans;
}
void add(int p, int x) {
while (p <= n) {
t[p] += x;
p += p & (-p);
}
}
// BIT end
int tot = 0;
struct Query {
int l, r, k, id, type; // set values to -1 when they are not used!
} q[N * 2], q1[N * 2], q2[N * 2];
void solve(int l, int r, int ql, int qr) {
if (ql > qr) return;
if (l == r) {
for (int i = ql; i <= qr; i++)
if (q[i].type == 2) ans[q[i].id] = l;
return;
}
int mid = (l + r) / 2, cnt1 = 0, cnt2 = 0;
for (int i = ql; i <= qr; i++) {
if (q[i].type == 1) {
if (q[i].l <= mid) {
add(q[i].id, 1);
q1[++cnt1] = q[i];
} else
q2[++cnt2] = q[i];
} else {
int x = sum(q[i].r) - sum(q[i].l - 1);
if (q[i].k <= x)
q1[++cnt1] = q[i];
else {
q[i].k -= x;
q2[++cnt2] = q[i];
}
}
}
// rollback changes
for (int i = 1; i <= cnt1; i++)
if (q1[i].type == 1) add(q1[i].id, -1);
// move them to the main array
for (int i = 1; i <= cnt1; i++) q[i + ql - 1] = q1[i];
for (int i = 1; i <= cnt2; i++) q[i + cnt1 + ql - 1] = q2[i];
solve(l, mid, ql, cnt1 + ql - 1);
solve(mid + 1, r, cnt1 + ql, qr);
}
pair<int, int> b[N];
int toRaw[N];
int main() {
scanf("%d%d", &n, &m);
// read and discrete input data
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
b[i].first = x;
b[i].second = i;
}
sort(b + 1, b + n + 1);
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (b[i].first != b[i - 1].first) cnt++;
a[b[i].second] = cnt;
toRaw[cnt] = b[i].first;
}
for (int i = 1; i <= n; i++) {
q[++tot] = {a[i], -1, -1, i, 1};
}
for (int i = 1; i <= m; i++) {
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
q[++tot] = {l, r, k, i, 2};
}
solve(0, cnt + 1, 1, tot);
for (int i = 1; i <= m; i++) printf("%d\n", toRaw[ans[i]]);
}
P2617 Dynamic Rankings
思路分析
把询问和修改放在一起,用树状数组维护。
代码
#include<iostream>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 5e5 + 10;
int n, m, zong;
struct Opt {
int x, y, k, type, id;
// ¶ÔÓÚѯÎÊ, type = 1, x, y ±íÊ¾Çø¼ä×óÓұ߽ç, k ±íʾѯÎÊµÚ k С
// ¶ÔÓÚÐÞ¸Ä, type = 0, x ±íʾÐÞ¸ÄλÖÃ, y ±íʾÐ޸ĺóµÄÖµ,
// k ±íʾµ±Ç°²Ù×÷ÊDzåÈë(1)»¹ÊDzÁ³ý(-1), ¸üÐÂÊ÷×´Êý×éʱʹÓÃ.
// id ¼Ç¼ÿ¸ö²Ù×÷ÔÏȵıàºÅ, Òò¶þ·Ö¹ý³ÌÖвÙ×÷˳Ðò»á±»´òÉ¢
};
Opt q[N], q1[N], q2[N];
// q ΪËùÓвÙ×÷,
// ¶þ·Ö¹ý³ÌÖÐ, ·Öµ½×ó±ßµÄ²Ù×÷´æµ½ q1 ÖÐ, ·Öµ½ÓұߵIJÙ×÷´æµ½ q2 ÖÐ.
int ans[N], t[N], a[N];
bool vis[N];
int lowbit(int x){
return x & -x;
}
void add(int p, int x){
for (int i = p; i <= n; i += lowbit(i)){
t[i] += x;
}
}
int query(int p){
int sum = 0;
for (int i = p; i; i -= lowbit(i)){
sum += t[i];
}
return sum;
} // Ê÷×´Êý×麯Êý, º¬Òå¼ûÌâ3
void solve(int l, int r, int L, int R)
// µ±Ç°µÄÖµÓò·¶Î§Îª [l,r], ´¦ÀíµÄ²Ù×÷µÄÇø¼äΪ [L,R]
{
if (l > r || L > R) return;
int cnt1 = 0, cnt2 = 0, m = (l + r) >> 1;
// cnt1, cnt2 ·Ö±ðΪ·Öµ½×ó±ß, ·Öµ½ÓұߵIJÙ×÷Êý
if (l == r) {
for (int i = L; i <= R; i++)
if (q[i].type == 1) ans[q[i].id] = l, vis[q[i].id] = 1;
return;
}
for (int i = L; i <= R; i++)
if (q[i].type == 1) { // ÊÇѯÎÊ: ½øÐзÖÀà
int t = query(q[i].y) - query(q[i].x - 1);
if (q[i].k <= t)
q1[++cnt1] = q[i];
else
q[i].k -= t, q2[++cnt2] = q[i];
} else
// ÊÇÐÞ¸Ä: ¸üÐÂÊ÷×´Êý×é & ·ÖÀà
if (q[i].y <= m)
add(q[i].x, q[i].k), q1[++cnt1] = q[i];
else
q2[++cnt2] = q[i];
for (int i = 1; i <= cnt1; i++)
if (q1[i].type == 0) add(q1[i].x, -q1[i].k); // Çå¿ÕÊ÷×´Êý×é
for (int i = 1; i <= cnt1; i++) q[L + i - 1] = q1[i];
for (int i = 1; i <= cnt2; i++)
q[L + cnt1 + i - 1] = q2[i]; // ½«ÁÙʱÊý×éÖеÄÔªËØºÏ²¢»ØÔÊý×é
solve(l, m, L, L + cnt1 - 1), solve(m + 1, r, L + cnt1, R);
return;
}
int main(){
n = read(), m = read();
for (int i = 1; i <= n; i++){
a[i] = read();
q[++zong] = (Opt){i, a[i], 1, 0, zong};
}
for (int i = 1; i <= m; i++){
char c;
cin >> c;
if (c == 'Q'){
q[++zong] = (Opt){read(), read(), read(), 1, zong};
}else{
int x = read(), y = read();
q[++zong] = (Opt){x, a[x], -1, 0, zong};
q[++zong] = (Opt){x, y, 1, 0, zong};
a[x] = y;
}
}
solve(0, 1000000000, 1, zong);
for (int i = n + 1; i <= zong; i++){
if (vis[i]) cout << ans[i] << endl;
}
return 0;
}
P3332 [ZJOI2013] K大数查询
思路分析
难度升级,我们发现,集合实际上就是有多个序列,那么就把树状数组改为线段树就好了。
代码
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 5e4 + 10;
int n, m;
struct node{
int l, r, c, id, type;
}q[N], q1[N], q2[N];
int ans[N];
bool vis[N];
struct tree{
int sum, tag;
}t[N << 2];
void pushup(int now){
t[now].sum = t[now << 1].sum + t[now << 1 | 1].sum;
}
void pushdown(int now, int l, int r){
int mid = (l + r) >> 1;
t[now << 1].sum += (mid - l + 1) * t[now].tag;
t[now << 1].tag += t[now].tag;
t[now << 1 | 1].sum += (r - mid) * t[now].tag;
t[now << 1 | 1].tag += t[now].tag;
t[now].tag = 0;
}
void modify(int now, int l, int r, int x, int y, int k){
if (x <= l && r <= y){
t[now].sum += (r - l + 1) * k;
t[now].tag += k;
return;
}
pushdown(now, l, r);
int mid = (l + r) >> 1;
if (x <= mid) modify(now << 1, l, mid, x, y, k);
if (mid + 1 <= y) modify(now << 1 | 1, mid + 1, r, x, y, k);
pushup(now);
}
int query(int now, int l, int r, int x, int y){
if (x <= l && r <= y){
return t[now].sum;
}
pushdown(now, l, r);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res += query(now << 1, l, mid, x, y);
if (mid + 1 <= y) res += query(now << 1 | 1, mid + 1, r, x, y);
return res;
}
void solve(int l, int r, int L, int R){
if (l > r || L > R) return;
if (l == r){
for (int i = L; i <= R; i++){
if (q[i].type == 2) ans[q[i].id] = l, vis[q[i].id] = 1;
}
return;
}
int cnt1 = 0, cnt2 = 0, mid = (l + r) >> 1;
for (int i = L; i <= R; i++){
if (q[i].type == 1){
if (q[i].c > mid) q2[++cnt2] = q[i], modify(1, 1, n, q[i].l, q[i].r, 1);
else q1[++cnt1] = q[i];
}else{
int t = query(1, 1, n, q[i].l, q[i].r);
if (q[i].c > t) q[i].c -= t, q1[++cnt1] = q[i];
else q2[++cnt2] = q[i];
}
}
for (int i = 1; i <= cnt1; i++) q[L + i - 1] = q1[i];
for (int i = 1; i <= cnt2; i++){
if (q2[i].type == 1) modify(1, 1, n, q2[i].l, q2[i].r, -1);
q[L + cnt1 + i - 1] = q2[i];
}
solve(l, mid, L, L + cnt1 - 1), solve(mid + 1, r, L + cnt1, R);
}
signed main(){
n = read(), m = read();
for (int i = 1; i <= m; i++){
int opt = read(), l = read(), r = read(), c = read();
if (opt == 1) q[i] = (node){l, r, c, i, 1};
else q[i] = (node){l, r, c, i, 2};
}
solve(-n, n, 1, m);
for (int i = 1; i <= m; i++){
if (vis[i]) cout << ans[i] << '\n';
}
return 0;
}

浙公网安备 33010602011771号