JOISC 2020 DAY1
Day 1
T1
随便猜个结论就行了。我猜的是将无论如何都成立的分成若干段,每一段一定是前缀贪心最小,后缀贪心最大。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int a[N],b[N],n;
typedef pair<int,int> pi;
vector<pi> s;
vector<pi> range;
int d1[N],d2[N];
inline pi check(int l,int r){
int mn = 0,cur=0;
d1[l-1]=mn;
pi rng;
for(int i=l;i<=r;i++){
if(cur<=min(a[i],b[i])){
cur=min(a[i],b[i]);
if(a[i]==cur)mn++;
}else{
cur=max(a[i],b[i]);
if(a[i]==cur)mn++;
}
d1[i]=mn;
}
d2[r+1]=0;
mn=0;
cur=0x3f3f3f3f;
for(int i=r;i>=l;i--){
if(max(a[i],b[i])<=cur){
cur=max(a[i],b[i]);
if(b[i]==max(a[i],b[i]));
else mn++;
}else {
cur=min(a[i],b[i]);
if(b[i]==cur);
else mn++;
}
d2[i]=mn;
}
int Mn = 0x3f3f3f3f, Mx = 0;
for(int i=l-1;i<=r;i++){
Mn = min(Mn,d1[i]+d2[i+1]);
Mx = max(Mx,d1[i]+d2[i+1]);
}
return pi(Mn,Mx);
}
int ans[N];
inline void Makel(int l,int r){
if(l>r)return ;
int cur=0;
for(int i=l;i<=r;i++){
if(cur<=min(a[i],b[i])){
cur=min(a[i],b[i]);
if(a[i]==cur)ans[i]=0;
else ans[i]=1;
}else{
cur=max(a[i],b[i]);
if(a[i]==cur)ans[i]=0;
else ans[i]=1;
}
}
}
inline void Maker(int l,int r){
if(l>r)return ;
int cur=0x3f3f3f3f;
for(int i=r;i>=l;i--){
if(max(a[i],b[i])<=cur)cur=max(a[i],b[i]);
else cur=min(a[i],b[i]);
if(b[i]==cur)ans[i]=1;
else ans[i]=0;
}
}
int main()
{
cin >> n;
for(int i=1;i<=n*2;i++)scanf("%d",&a[i]);
for(int i=1;i<=n*2;i++)scanf("%d",&b[i]);
int lst = 1;
for(int i=1;i<n*2;i++){
if(min(a[i],b[i])>max(a[i+1],b[i+1])){
puts("-1");
return 0;
}
}
for(int i=1;i<=n*2;i++){
if(i==n*2||max(a[i],b[i])<=min(a[i+1],b[i+1])){
s.push_back(pi(lst,i));
range.push_back(check(lst,i));
lst=i+1;
}
}
int sz = range.size();
for(int i=1;i<sz;i++)range[i].first+=range[i-1].first, range[i].second+=range[i-1].second;
if(range[sz-1].first<=n&&range[sz-1].second>=n){
}else {
puts("-1");
return 0;
}
int req = n;
for(int i=sz-1;~i;i--){
pi R=check(s[i].first,s[i].second);
int prel=i==0?0:range[i-1].first,prer=i==0?0:range[i-1].second;
for(int j=s[i].first-1;j<=s[i].second;++j){
int d=d1[j]+d2[j+1];
if(prel<=req-d&&prer>=req-d){
Makel(s[i].first,j);
Maker(j+1,s[i].second);
req-=d;
break;
}
}
}
for(int i=2;i<=n*2;i++){
int c1=ans[i-1]?b[i-1]:a[i-1];
int c2=ans[i]?b[i]:a[i];
if(c1>c2){
puts("-1");
return 0;
}
}
for(int i=1;i<=n*2;i++){
printf("%c",ans[i]?'B':'A');
}
puts("");
}
T3
考虑操作相当于
- 插入一个区间
- 将 \(l\le p \le r\) 的区间的 \(l\) 设置为 \(p\)
- 将 \(l\le p \le r\) 的区间的 \(r\) 设置为 \(p\)
我们将区间按照 \(mid\) 分成两个部分,左边维护第二个操作,右边维护第三个操作,当有越过 \(mid\) 的操作的时候就将其重构,这个东西可以用平衡树简单维护,重构次数是一个 \(log\) 的,故复杂度 \(n\log^2\)。
代码比较菜被卡常了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int Len, n, Q;
const int N = 2e6+5;
mt19937 rnd(142857);
struct Node{
int ch[2], fa;
int key, Mid, minl ,l, ltag, maxr, r, rtag;
void clear(){ ch[0]=ch[1]=fa=0; }
}t[N];
inline int son(int x){return t[t[x].fa].ch[1]==x;}
inline void con(int x,int y,int z){t[x].ch[y]=z,t[z].fa=x;}
inline void pushtag(int x,int _l,int _r){
if(_l!=0)t[x].minl=max(t[x].minl,_l),t[x].l=max(t[x].l,_l),t[x].ltag=max(t[x].ltag,_l);
if(_r!=1000000000)t[x].maxr=min(t[x].maxr,_r),t[x].r=min(t[x].r,_r),t[x].rtag=min(t[x].rtag,_r);
}// minl -> max, maxr -> min
inline void pushdown(int x){
if(t[x].ltag==0&&t[x].rtag==1000000000)return;
if(t[x].ch[0])pushtag(t[x].ch[0],t[x].ltag,t[x].rtag);
if(t[x].ch[1])pushtag(t[x].ch[1],t[x].ltag,t[x].rtag);
t[x].ltag=0,t[x].rtag=1000000000;
}
inline void pushup(int x){
t[x].minl=t[x].l,t[x].maxr=t[x].r;
if(t[x].ch[0])t[x].minl=min(t[t[x].ch[0]].minl,t[x].minl),t[x].maxr=max(t[t[x].ch[0]].maxr,t[x].maxr);
if(t[x].ch[1])t[x].minl=min(t[t[x].ch[1]].minl,t[x].minl),t[x].maxr=max(t[t[x].ch[1]].maxr,t[x].maxr);
}
inline int merge(int x,int y){
pushdown(x), pushdown(y);
if(!x||!y)return x|y;
if(t[x].Mid > t[y].Mid) swap(x, y);
if(t[x].key < t[y].key){
con(y,0,merge(x,t[y].ch[0]));
pushup(y);return y;
}else{
con(x,1,merge(t[x].ch[1],y));
pushup(x);return x;
}
}
typedef pair<int,int> pi;
inline pi split(int x,int k){
if(!x)return pi(0,0);
pushdown(x);
if(t[x].Mid<=k){
t[t[x].ch[1]].fa=0;
pi r = split(t[x].ch[1],k);
con(x,1,r.first);pushup(x);
return pi(x,r.second);
}else{
t[t[x].ch[0]].fa=0;
pi r = split(t[x].ch[0],k);
con(x,0,r.second);pushup(x);
return pi(r.first,x);
}
}
inline void pushnow(int x){
if(t[x].fa)pushnow(t[x].fa);
pushdown(x);
}
inline void del(int &rt,int id){
// pushnow(id);
t[t[id].ch[0]].fa=t[t[id].ch[1]].fa=0;
int r = merge(t[id].ch[0],t[id].ch[1]);
int f = t[id].fa;
if(f){con(f,son(id),r);}
else t[r].fa=0,rt=r;
t[id].clear();
for(int q=f;q;q=t[q].fa)pushup(q);
}
inline int findlmin(int x){
pushdown(x);
if(t[x].minl==t[x].l)return x;
if(!t[x].ch[0])return findlmin(t[x].ch[1]);
if(t[t[x].ch[0]].minl==t[x].minl)return findlmin(t[x].ch[0]);
else return findlmin(t[x].ch[1]);
}
inline int findrmax(int x){
pushdown(x);
if(t[x].maxr==t[x].r)return x;
if(!t[x].ch[0])return findrmax(t[x].ch[1]);
if(t[t[x].ch[0]].maxr==t[x].maxr)return findrmax(t[x].ch[0]);
else return findrmax(t[x].ch[1]);
}
int Root;
inline void rebuild(int x,int l,int r){
t[x].key=rnd();
t[x].clear();t[x].Mid=(l+r)>>1;
t[x].l=l,t[x].r=r;
t[x].ltag=0,t[x].rtag=1000000000;pushup(x);
}
inline int ins(int Root,int x){
pi r = split(Root,t[x].Mid);
return merge(r.first,merge(x,r.second));
}
inline int read(){
char c=getchar();int x=0;
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
short buf[20],top;
inline void output(int x,char s){
if(!x){
putchar('0');
putchar(s);
return ;
}top=0;
while(x){
buf[++top]=x%10,x/=10;
}while(top){
putchar('0'+buf[top--]);
}putchar(s);
}
int main()
{
Len=read(), n=read(), Q = read();
for(int i=1;i<=n;i++){
int l=read(),r=read();
r=Len-r;
rebuild(i,l,r);
Root=ins(Root,i);
}
while(Q--){
int op=read();
if(op==1){
int id=read();
pushnow(id);
output(t[id].l, ' ');
output(Len-t[id].r,'\n');
// printf("%d %d\n",t[id].l,Len-t[id].r);
}else if(op==2){
int L=read();//l->max
L=Len-L;
pi R = split(Root, L-1);
Root = 0;
int lft = R.first, rgt = R.second;
if(rgt)pushtag(rgt, L, 1000000000);
while(1){
if(!lft)break;
int id = findrmax(lft);
if(t[id].r>=L){
del(lft,id);
rebuild(id,L,t[id].r);
if(t[id].l!=t[id].r)
rgt=ins(rgt,id);
}else break;
}
Root = merge(lft,rgt);
}else if(op==3){
int L=read();//r->min
pi R = split(Root, L);
Root = 0;
int lft = R.first, rgt = R.second;
if(lft)pushtag(lft, 0, L);
while(1){
if(!rgt)break;
int id = findlmin(rgt);
if(t[id].l<=L){
del(rgt,id);
rebuild(id,t[id].l,L);
if(t[id].l!=t[id].r)
lft=ins(lft,id);
}else break;
}
Root = merge(lft,rgt);
}else{
int l=read(),r=read();;r=Len-r;
++n;rebuild(n,l,r);
Root = ins(Root, n);
}
}
cerr << clock() << endl;
}