「JOISC 2020 Day1」扫除 (分治)(线段树)(平衡树)

2024-01-30 01:08

本文主要是介绍「JOISC 2020 Day1」扫除 (分治)(线段树)(平衡树),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门

  • 首先考虑 S u b t a s k 3 Subtask\ 3 Subtask 3,这些点是单调的,所以用线段树维护区间赋值

  • S u b t a s k 4 Subtask\ 4 Subtask 4,没有插入,考虑如果一个点被推到一个地方,那么它与其它的相对顺序就不会变,所以我们用动态开点线段树来找点,用一个平衡树来维护被推的点,平衡树支持插入,区间赋值

  • 对于有插入的情况,即对于 k k k 号询问,需要把 [ l k , r k ] [l_k,r_k] [lk,rk] 的修改对 k k k 做一遍,那么我们线段树分治,每次处理 [ l , r ] [l,r] [l,r] 的时候把 [ l , r ] [l,r] [l,r] 的修改做一遍统计对这些询问的影响
    复杂度 O ( ( M + Q ) log ⁡ N log ⁡ Q ) O((M+Q)\log N\log Q) O((M+Q)logNlogQ) C o d e Code Code,太慢了没卡过!

  • 其实还有一种方法,就是考虑如果只有从左向右推的话,最后 x x x 的坐标是个关于 y y y 的分段函数,我们按 y y y 和修改的高度从大到小排序,每一个修改可以表示为将 ≤ x \le x x 的一段区间推到 x x x,可以用线段树维护,考虑有上下推的时候对一个左右推的干扰,上下推可以把一些点扫走,于是左右推的实质是将 [ l , r ] [l,r] [l,r] 的点推到 r r r,预处理出这个 l l l 就可以了,这个 l l l 是之前出现的上下推的宽度的最大值,同样用线段树维护,具体可以看代码

#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pi;
cs int N = 2e6 + 50;
namespace IO{inline char gc(){static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}template<typename T>T Read(){char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;}inline int read(){return Read<int>();}
} using namespace IO;
int n, m, Q;
int x[N], y[N], opt[N], vl[N];
pi as[N];
cs int M = N * 30;
cs int INF = 1e9 + 7;
struct SegmenTree{#define mid ((l+r)>>1)int ls[M], rs[M], mx[M], rt, nd;vector<pi> S;void clr(){ rt=nd=0; }int newnode(){ int x=++nd; ls[x]=rs[x]=mx[x]=0; return x; }void modify(int &x, int l, int r, int L, int R, int v){if(L>R) return;if(!x) x=newnode(); if(mx[x]>=v) return;if(L<=l&&r<=R){ mx[x]=v; return; } if(L<=mid) modify(ls[x],l,mid,L,R,v);if(R>mid) modify(rs[x],mid+1,r,L,R,v);}int query(int x, int l, int r, int p){if(!x) return 0; if(l==r) return mx[x];if(p<=mid) return max(mx[x],query(ls[x],l,mid,p));else return max(mx[x],query(rs[x],mid+1,r,p));}#undef mid
}X, Y;
void upt(int op, int vl){int t = op ? X.query(X.rt,0,n,vl) : Y.query(Y.rt,0,n,vl);op ? Y.S.pb(pi(vl,t)) : X.S.pb(pi(vl,t)); op ? Y.modify(Y.rt,0,n,t,n-vl-1,vl+1) : X.modify(X.rt,0,n,t,n-vl-1,vl+1);
}
namespace SGT{bool vis[N];vector<pi> S[N<<2];#define mid ((l+r)>>1)void ins(int x, int l, int r, int L, int R, pi v){if(L<=l&&r<=R){ S[x].pb(v); return; }if(L<=mid) ins(x<<1,l,mid,L,R,v); if(R>mid) ins(x<<1|1,mid+1,r,L,R,v);}void subwork(int x, int l, int r){if(!S[x].size()) return;X.clr(), Y.clr(); X.S.clear(), Y.S.clear();for(int i=l; i<=r; i++) if(opt[i]==2||opt[i]==3) upt(opt[i]==2,vl[i]);X.clr(), Y.clr();sort(S[x].begin(),S[x].end(),[](cs pi &a, cs pi &b){ return ::y[a.fi] > ::y[b.fi]; });sort(Y.S.begin(), Y.S.end(), [](cs pi &a, cs pi &b){ return a.fi > b.fi; }); int j=0; for(auto c : S[x]){int u = c.fi;for(;j<(int)Y.S.size()&&Y.S[j].fi>=::y[u];j++){Y.modify(Y.rt,0,n,Y.S[j].se,n-Y.S[j].fi,n-Y.S[j].fi);} ::x[u]=max(::x[u],Y.query(Y.rt,0,n,::x[u]));}sort(S[x].begin(),S[x].end(),[](cs pi &a, cs pi &b){ return ::x[a.fi] > ::x[b.fi]; });sort(X.S.begin(), X.S.end(), [](cs pi &a, cs pi &b){ return a.fi > b.fi; }); j=0; for(auto c : S[x]){int u = c.fi;for(;j<(int)X.S.size()&&X.S[j].fi>=::x[u];j++){X.modify(X.rt,0,n,X.S[j].se,n-X.S[j].fi,n-X.S[j].fi);} ::y[u]=max(::y[u],X.query(X.rt,0,n,::y[u]));}for(auto c : S[x]) as[c.se]=pi(::x[c.fi],::y[c.fi]);}void work(int x, int l, int r){subwork(x,l,r); if(l^r) work(x<<1,l,mid), work(x<<1|1,mid+1,r);} #undef mid
}
int main(){n=read(), m=read(), Q=read();for(int i=1; i<=m; i++) x[i]=read(), y[i]=read();static int las[N]; int q=0;for(int i=1; i<=Q; i++){opt[i]=read();if(opt[i]==1){ int x=read(); SGT::ins(1,1,Q,las[x]+1,i,pi(x,++q)); las[x]=i; }if(opt[i]==2||opt[i]==3) vl[i]=read();if(opt[i]==4) x[++m]=read(), y[m]=read(), las[m]=i;}SGT::work(1,1,Q); for(int i=1; i<=q; i++) cout<<as[i].fi<<" "<<as[i].se<<'\n';return 0;
}

这篇关于「JOISC 2020 Day1」扫除 (分治)(线段树)(平衡树)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658676

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

HDU4737线段树

题目大意:给定一系列数,F(i,j)表示对从ai到aj连续求或运算,(i<=j)求F(i,j)<=m的总数。 const int Max_N = 100008 ;int sum[Max_N<<2] , x[Max_N] ;int n , m ;void push_up(int t){sum[t] = sum[t<<1] | sum[t<<1|1] ;}void upd

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;