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;
}
posted @ 2020-03-24 18:31  jerome_wei  阅读(649)  评论(0编辑  收藏  举报